12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227 |
- //---------------------------------------------------------------------------
- #include <vcl.h>
- #pragma hdrstop
- #include <malloc.h>
- #include <stdio.h>
- #include <wincrypt.h>
- #include <apr_hash.h>
- #include <apr_strings.h>
- #include <apr_tables.h>
- #include <apr_file_io.h>
- #include <apr_portable.h>
- #include <apr_atomic.h>
- #include <ne_basic.h>
- #include <ne_auth.h>
- #include <ne_compress.h>
- #include <ne_props.h>
- #include <ne_defs.h>
- #include <ne_uri.h>
- #include <ne_session.h>
- #include <ne_request.h>
- #include <ne_xml.h>
- #include <ne_pkcs11.h>
- #include "WebDAVFileSystem.h"
- #include "Interface.h"
- #include "Common.h"
- #include "Exceptions.h"
- #include "Terminal.h"
- #include "TextsCore.h"
- #include "SecureShell.h"
- #include "FileZillaIntf.h"
- #include "HelpCore.h"
- //---------------------------------------------------------------------------
- #pragma package(smart_init)
- //---------------------------------------------------------------------------
- const int tfFirstLevel = 0x01;
- const int tfAutoResume = 0x02;
- //---------------------------------------------------------------------------
- struct TSinkFileParams
- {
- UnicodeString TargetDir;
- const TCopyParamType * CopyParam;
- int Params;
- TFileOperationProgressType * OperationProgress;
- bool Skipped;
- unsigned int Flags;
- };
- //---------------------------------------------------------------------------
- struct TFileTransferData
- {
- TFileTransferData()
- {
- Params = 0;
- AutoResume = false;
- OverwriteResult = -1;
- CopyParam = NULL;
- }
- UnicodeString FileName;
- int Params;
- bool AutoResume;
- int OverwriteResult;
- const TCopyParamType * CopyParam;
- };
- //---------------------------------------------------------------------------
- struct TClipboardHandler
- {
- UnicodeString Text;
- void __fastcall Copy(TObject * /*Sender*/)
- {
- CopyToClipboard(Text);
- }
- };
- //---------------------------------------------------------------------------
- namespace webdav {
- #pragma warn -8004
- const AnsiString __cdecl Format(const char * format, va_list args)
- {
- int len = AnsiString().vprintf(format, args);
- AnsiString Result;
- Result.SetLength(len + 1);
- vsprintf(&Result[1], format, args);
- return Result.c_str();
- }
- const AnsiString __cdecl Format(const char * format, ...)
- {
- va_list args;
- va_start(args, format);
- AnsiString Result = Format(format, args);
- va_end(args);
- return Result;
- }
- //---------------------------------------------------------------------------
- struct auth_baton_t;
- struct vtable_t;
- struct stream_t;
- struct client_ctx_t;
- struct auth_iterstate_t;
- //---------------------------------------------------------------------------
- typedef enum tristate_t
- {
- tristate_false = 2,
- tristate_true,
- tristate_unknown
- } tristate_t;
- //------------------------------------------------------------------------------
- // Userdata for the `proxy_auth' function.
- struct proxy_auth_baton_t
- {
- const char * username; // Cannot be NULL, but "" is okay.
- const char * password; // Cannot be NULL, but "" is okay.
- };
- //------------------------------------------------------------------------------
- // from svn_types.h
- typedef error_t (*cancel_func_t)(void * cancel_baton);
- //------------------------------------------------------------------------------
- // from svn_ra.h
- typedef void (*progress_notify_func_t)(
- apr_off_t progress,
- apr_off_t total,
- void * baton,
- apr_pool_t * pool);
- typedef error_t (*get_client_string_func_t)(void * baton,
- const char ** name,
- apr_pool_t * pool);
- typedef struct callbacks2_t
- {
- auth_baton_t * auth_baton;
- progress_notify_func_t progress_func;
- void * progress_baton;
- cancel_func_t cancel_func;
- get_client_string_func_t get_client_string;
- } callbacks2_t;
- typedef struct callback_baton_t
- {
- client_ctx_t * ctx;
- apr_pool_t * pool;
- } callback_baton_t;
- //------------------------------------------------------------------------------
- // from ra_loader.h
- typedef error_t (*init_func_t)(const vtable_t ** vtable,
- apr_pool_t * pool);
- //------------------------------------------------------------------------------
- // from svn_string.h
- // A simple counted string.
- typedef struct string_t
- {
- const char * data; //< pointer to the bytestring
- apr_size_t len; //< length of bytestring
- } string_t;
- // A buffered string, capable of appending without an allocation and copy
- // for each append.
- typedef struct stringbuf_t
- {
- apr_pool_t * pool;
- char * data;
- apr_size_t len;
- apr_size_t blocksize;
- } stringbuf_t;
- //------------------------------------------------------------------------------
- // from ra_neon.h
- // Rename these types and constants to abstract from Neon
- #define NEON_XML_DECLINE NE_XML_DECLINE
- #define NEON_XML_INVALID NE_XML_ABORT
- #define NEON_XML_CDATA (1<<1)
- #define NEON_XML_COLLECT ((1<<2) | NEON_XML_CDATA)
- // Related to anonymous enum below?
- typedef int neon_xml_elmid;
- typedef struct neon_xml_elm_t
- {
- const char * nspace;
- const char * name;
- neon_xml_elmid id;
- // Processing flags for this namespace:tag.
- // 0 (zero) - regular element, may have children,
- // NEON_XML_CDATA - child-less element,
- // NEON_XML_COLLECT - complete contents of such element must be
- // collected as CDATA, includes *_CDATA flag.
- unsigned int flags;
- } neon_xml_elm_t;
- typedef struct neon_session_t
- {
- apr_pool_t * pool;
- stringbuf_t * url; // original, unparsed session url
- ne_uri root; // parsed version of above
- const char * webdav_root; // URL for WebDAV resource root
- ne_session * ne_sess; // HTTP session to server
- const callbacks2_t * callbacks; // callbacks to get auth data
- void * callback_baton;
- auth_iterstate_t * auth_iterstate; // state of authentication retries
- bool auth_used; // Save authorization state after
- // successful usage
- auth_iterstate_t * p11pin_iterstate; // state of PKCS#11 pin retries
- bool compression; // should we use http compression?
- progress_notify_func_t progress_func;
- void * progress_baton;
- apr_off_t total_progress; // Total number of bytes sent in this
- // session with a -1 total marker
- apr_hash_t * capabilities;
- } neon_session_t;
- typedef struct neon_request_t
- {
- ne_request * ne_req; // neon request structure
- ne_session * ne_sess; // neon session structure
- neon_session_t * sess; // DAV session structure
- const char * method;
- const char * url;
- int rv; // Return value from
- // ne_request_dispatch() or -1 if
- // not dispatched yet.
- int code; // HTTP return code, or 0 if none
- const char * code_desc; // Textual description of CODE
- error_t err; // error encountered while executing
- // the request
- bool marshalled_error; // TRUE if the error was server-side
- apr_pool_t * pool; // where this struct is allocated
- apr_pool_t * iterpool; // iteration pool
- // for use within callbacks
- } neon_request_t;
- // Related to neon_xml_elmid?
- // add WEBDAV_NEON_ to these to prefix conflicts with (sys) headers?
- enum
- {
- // Redefine Neon elements
- // With the new API, we need to be able to use element id also as a return
- // value from the new `startelm' callback, hence all element ids must be
- // positive. Root element id is the only id that is not positive, it's zero.
- // `Root state' is never returned by a callback, it's only passed into it.
- // Therefore, negative element ids are forbidden from now on.
- ELEM_unknown = 1, // was (-1), see above why it's (1) now
- ELEM_root = NE_XML_STATEROOT, // (0)
- ELEM_UNUSED = 100,
- ELEM_207_first = ELEM_UNUSED,
- ELEM_multistatus = ELEM_207_first,
- ELEM_response = ELEM_207_first + 1,
- ELEM_responsedescription = ELEM_207_first + 2,
- ELEM_href = ELEM_207_first + 3,
- ELEM_propstat = ELEM_207_first + 4,
- ELEM_prop = ELEM_207_first + 5, // `prop' tag in the DAV namespace
- ELEM_status = ELEM_207_first + 6,
- ELEM_207_UNUSED = ELEM_UNUSED + 100,
- ELEM_PROPS_UNUSED = ELEM_207_UNUSED + 100,
- // DAV elements
- ELEM_collection = ELEM_207_UNUSED,
- ELEM_comment,
- ELEM_creationdate,
- ELEM_creator_displayname,
- ELEM_options_response,
- ELEM_set_prop,
- ELEM_remove_prop,
- ELEM_resourcetype,
- ELEM_get_content_length,
- ELEM_get_last_modified,
- ELEM_updated_set,
- ELEM_error,
- ELEM_human_readable,
- };
- // The session object.
- struct session_t
- {
- const vtable_t * vtable;
- // Pool used to manage this session.
- apr_pool_t * pool;
- // Private data for the RA implementation.
- void * priv;
- };
- typedef std::vector<TListDataEntry> listdataentry_vector_t;
- // Baton used when listing directory entries.
- typedef struct list_func_baton_t
- {
- bool verbose;
- listdataentry_vector_t * entries;
- session_t * session;
- apr_pool_t * pool;
- } list_func_baton_t;
- //------------------------------------------------------------------------------
- // timeout (in seconds)
- #define DEFAULT_HTTP_TIMEOUT 10
- #define WEBDAV_ERR_DAV_SOCK_INIT 1000
- #define WEBDAV_ERR_XML_MALFORMED 1001
- #define WEBDAV_ERR_DAV_OPTIONS_REQ_FAILED 1002
- #define WEBDAV_ERR_DAV_REQUEST_FAILED 1003
- #define WEBDAV_ERR_INCORRECT_PARAMS 1004
- #define WEBDAV_ERR_FS_NOT_FOUND 1005
- #define WEBDAV_ERR_FS_PROP_BASEVALUE_MISMATCH 1006
- #define WEBDAV_ERR_DAV_FORBIDDEN 1010
- #define WEBDAV_ERR_DAV_RELOCATED 1011
- #define WEBDAV_ERR_NOT_AUTHORIZED 1012
- #define WEBDAV_ERR_ILLEGAL_URL 1013
- #define WEBDAV_ERR_DAV_NOT_IMPLEMENTED 1014
- #define WEBDAV_ERR_NOT_IMPLEMENTED 1015
- #define WEBDAV_ERR_AUTHN_NO_PROVIDER 1020
- #define WEBDAV_ERR_CLIENT_CYCLE_DETECTED 1021
- #define WEBDAV_ERR_DAV_MALFORMED_DATA 1022
- #define WEBDAV_ERR_IO_PIPE_WRITE_ERROR 1023
- #define WEBDAV_ERR_BAD_DATE 1024
- #define WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES 1025
- #define WEBDAV_ERR_ROOT_URL_MISMATCH 1027
- #define WEBDAV_ERR_BAD_FILENAME 1028
- #define WEBDAV_ERR_ENTRY_MISSING_URL 1029
- #define WEBDAV_ERR_FS_NOT_FILE 1030
- #define WEBDAV_ERR_ATOMIC_INIT_FAILURE 1033
- #define WEBDAV_ERR_IO_UNIQUE_NAMES_EXHAUSTED 1034
- #define WEBDAV_ERR_STREAM_SEEK_NOT_SUPPORTED 1035
- #define WEBDAV_ERR_BAD_CONFIG_VALUE 1040
- #define WEBDAV_ERR_CANCELLED 1050
- #define WEBDAV_ERR_DAV_INVALID_CONFIG_VALUE 1051
- #define WEBDAV_ERR_DAV_PROPPATCH_FAILED 1060
- #define WEBDAV_ERR_CANNOT_PUT_FILE 1061
- #define WEBDAV_ERR_CANNOT_DELETE_FILE 1062
- #define WEBDAV_ERR_CANNOT_MKCOL 1063
- #define WEBDAV_ERR_CANNOT_MOVE 1064
- #define WEBDAV_ERR_CANNOT_PROPFIND 1065
- #define WEBDAV_ERR_BAD_PARAM 1070
- // The application doesn't want any providers to save credentials
- // to disk. Property value is irrelevant; only property's existence
- // matters.
- #define AUTH_PARAM_NO_AUTH_CACHE AUTH_PARAM_PREFIX "no-auth-cache"
- // #define HASH_KEY_STRING ""
- #define MAX_REDIRECT_ATTEMPTS 3 // TODO: Make configurable.
- //---------------------------------------------------------------------------
- // #define WEBDAV_ARRAY_IDX(ary,i,type) ((type)(ary)[i])
- #define WEBDAV_NO_ERROR 0
- #define WEBDAV_UNKNOWN_ERROR 1
- #define WEBDAV_ERR(expr) \
- do { \
- webdav::error_t err__temp = (expr); \
- if (err__temp) \
- return err__temp; \
- } while (0)
- // A statement macro, very similar to WEBDAV_ERR.
- // This macro will wrap the error with the specified text before
- // returning the error.
- #define WEBDAV_ERR_W(expr, wrap_msg) \
- do { \
- webdav::error_t err__temp = (expr); \
- if (err__temp) \
- return webdav::error_create(err__temp, NULL, wrap_msg); \
- } while (0)
- #define WEBDAV_ERR_ASSERT(expr) \
- do { \
- if (!(expr)) \
- WEBDAV_ERR(WEBDAV_UNKNOWN_ERROR); \
- } while (0)
- #define error_trace(expr) (expr)
- // Create a pool as a subpool of parent_pool
- #define webdav_pool_create(parent_pool) webdav::pool_create_ex(parent_pool, NULL)
- #define webdav_pool_clear apr_pool_clear
- // Destroy a pool and all of its children.
- // This define for webdav_pool_destroy exists for symmetry and
- // completeness.
- #define webdav_pool_destroy apr_pool_destroy
- // Destroy request REQ and any associated resources
- #define neon_request_destroy(req) webdav_pool_destroy((req)->pool)
- // Statement macro to set the request error,
- // making sure we don't leak any in case we encounter more than one error.
- // Sets the 'err' field of REQ to the value obtained by evaluating NEW_ERR.
- #define NEON_REQ_ERR(req, new_err) \
- do { \
- error_t err__tmp = (new_err); \
- if ((req)->err && !(req)->marshalled_error) \
- error_clear(&err__tmp); \
- else if (err__tmp) \
- { \
- error_clear(&(req)->err); \
- (req)->err = err__tmp; \
- (req)->marshalled_error = false; \
- } \
- } while (0)
- //===========================================================================
- //------------------------------------------------------------------------------
- // from error.c
- static void
- error_clear(error_t * err)
- {
- if (err) *err = 0;
- }
- static error_t
- make_error_internal(
- apr_status_t apr_err,
- error_t * child)
- {
- error_t new_error = apr_err;
- return new_error;
- }
- static error_t
- error_create(
- apr_status_t apr_err,
- error_t * child,
- const char * message)
- {
- return apr_err;
- }
- static error_t
- error_createf(
- apr_status_t apr_err,
- error_t * child,
- const char * fmt,
- ...)
- {
- va_list args;
- va_start(args, fmt);
- AnsiString Message = Format(fmt, args);
- va_end(args);
- AnsiString Message2 = Format("Error, code: %d, message: %s", apr_err, Message.c_str());
- throw ExtException(UnicodeString(Message2), NULL);
- }
- static error_t
- error_wrap_apr(
- apr_status_t status,
- const char * fmt,
- ...)
- {
- error_t err = 0;
- va_list args;
- err = make_error_internal(status, NULL);
- va_start(args, fmt);
- AnsiString Message = Format(fmt, args);
- va_end(args);
- err = error_create(err, NULL, Message.c_str());
- return err;
- }
- //------------------------------------------------------------------------------
- // from utils.c
- // a cleanup routine attached to the pool that contains the RA session
- // root URI.
- static apr_status_t
- cleanup_uri(void * uri)
- {
- ne_uri_free(static_cast<ne_uri *>(uri));
- return APR_SUCCESS;
- }
- static error_t
- parse_url(
- const char * url, ne_uri * uri)
- {
- if (ne_uri_parse(url, uri) ||
- (uri->host == NULL) || (uri->path == NULL) || (uri->scheme == NULL))
- {
- ne_uri_free(uri);
- return 0;
- }
- if (uri->port == 0)
- uri->port = ne_uri_defaultport(uri->scheme);
- return 1;
- }
- static error_t
- parse_ne_uri(
- ne_uri ** uri,
- const char * webdav_url,
- apr_pool_t * pool)
- {
- // Sanity check the URI
- *uri = static_cast<ne_uri *>(apr_pcalloc(pool, sizeof(**uri)));
- if (!parse_url(webdav_url, *uri))
- {
- return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "URL '%s' is malformed or the "
- "scheme or host or path is missing", webdav_url);
- }
- // make sure we eventually destroy the uri
- apr_pool_cleanup_register(pool, *uri, cleanup_uri, apr_pool_cleanup_null);
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from svn_types.h
- #define atoui64(X) ((apr_uint64_t) apr_atoi64(X))
- // An indication that you are interested in the kind field
- #define WEBDAV_DIRENT_KIND 0x00001
- // An indication that you are interested in the size field
- #define WEBDAV_DIRENT_SIZE 0x00002
- // An indication that you are interested in the time field
- #define WEBDAV_DIRENT_TIME 0x00010
- // A combination of all the dirent fields
- #define WEBDAV_DIRENT_ALL ~((apr_uint32_t ) 0)
- // The various types of nodes in filesystem.
- typedef enum node_kind_t
- {
- // absent
- node_none,
- // regular file
- node_file,
- // directory
- node_dir,
- // something's here, but we don't know what
- node_unknown
- } node_kind_t;
- // A general directory entry.
- typedef struct dirent_t
- {
- // node kind
- node_kind_t kind;
- // length of file text, or 0 for directories
- apr_int64_t size;
- // time of mod-time
- apr_time_t time;
- } dirent_t;
- typedef enum depth_t
- {
- // Just the named directory D, no entries. Updates will not pull in
- // any files or subdirectories not already present.
- depth_empty = 0,
- // D + its file children, but not subdirs. Updates will pull in any
- // files not already present, but not subdirectories.
- depth_files = 1,
- // D + immediate children (D and its entries). Updates will pull in
- // any files or subdirectories not already present; those
- // subdirectories' this_dir entries will have depth-empty.
- depth_immediates = 2,
- // D + all descendants (full recursion from D). Updates will pull
- // in any files or subdirectories not already present; those
- // subdirectories' this_dir entries will have depth-infinity.
- // Equivalent to the pre-1.5 default update behavior.
- depth_infinity = 3
- } depth_t;
- //------------------------------------------------------------------------------
- // from utf.h
- static error_t
- utf_cstring_to_utf8(
- const char ** dest,
- const char * src,
- apr_pool_t * pool);
- static error_t
- utf_cstring_from_utf8(
- const char ** dest,
- const char * src,
- apr_pool_t * pool);
- // Local wrapper of path_cstring_from_utf8() that does no copying on
- // operating systems where APR always uses utf-8 as native path format
- static error_t
- cstring_from_utf8(
- const char ** path_apr,
- const char * path_utf8,
- apr_pool_t * pool);
- //------------------------------------------------------------------------------
- // from ra_neon.h
- #ifdef WEBDAV_DEBUG
- #define DEBUG_CR "\n"
- #else
- #define DEBUG_CR ""
- #endif
- #define NEON_DEPTH_ZERO 0
- #define NEON_DEPTH_ONE 1
- #define NEON_DEPTH_INFINITE -1
- // NEON_PROP_*: properties that we fetch from the server
- // These are simply symbolic names for some standard properties that we fetch.
- #define NEON_PROP_CREATIONDATE "DAV:creationdate"
- #define NEON_PROP_GETCONTENTLENGTH "DAV:getcontentlength"
- typedef struct neon_resource_t
- {
- // what is the URL for this resource
- const char * url;
- // is this resource a collection? (from the DAV:resourcetype element)
- int is_collection;
- // PROPSET: NAME -> VALUE (const char * -> const string_t *)
- apr_hash_t * propset;
- // --- only used during response processing ---
- // when we see a DAV:href element, what element is the parent?
- int href_parent;
- apr_pool_t * pool;
- } neon_resource_t;
- // Our equivalent of ne_xml_startelm_cb, the difference being that it
- // returns errors in a error_t, and returns the element type via
- // ELEM. To ignore the element *ELEM should be set to
- // NEON_XML_DECLINE and WEBDAV_NO_ERROR should be returned.
- // *ELEM can be set to NEON_XML_INVALID to indicate invalid XML
- // (and abort the parse).
- typedef error_t (*neon_startelm_cb_t)(int * elem,
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts);
- // Our equivalent of ne_xml_cdata_cb, the difference being that it returns
- // errors in a error_t.
- typedef error_t (*neon_cdata_cb_t)(void * baton,
- int state,
- const char * cdata,
- size_t len);
- // Our equivalent of ne_xml_endelm_cb, the difference being that it returns
- // errors in a error_t.
- typedef error_t (*neon_endelm_cb_t)(void * baton,
- int state,
- const char * nspace,
- const char * name);
- static ne_xml_parser *
- neon_xml_parser_create(
- neon_request_t * req,
- ne_accept_response accpt,
- neon_startelm_cb_t startelm_cb,
- neon_cdata_cb_t cdata_cb,
- neon_endelm_cb_t endelm_cb,
- void * baton);
- static error_t
- neon_request_dispatch(
- int * code_p,
- neon_request_t * req,
- apr_hash_t * extra_headers,
- const char * body,
- int okay_1,
- int okay_2,
- bool check_errors,
- apr_pool_t * pool);
- static error_t
- neon_check_parse_error(
- const char * method,
- ne_xml_parser * xml_parser,
- const char * url);
- static error_t
- neon_request_create(
- neon_request_t ** request,
- neon_session_t * sess,
- const char * method, const char * url,
- apr_pool_t * pool);
- static const neon_xml_elm_t *
- neon_lookup_xml_elem(
- const neon_xml_elm_t * table,
- const char * nspace,
- const char * name);
- static error_t
- neon_xml_collect_cdata(
- void * baton, int state,
- const char * cdata, size_t len);
- static const char *
- neon_request_get_location(
- neon_request_t * request,
- apr_pool_t * pool);
- // Our version of ne_block_reader, which returns an
- // error_t instead of an int.
- typedef error_t (*neon_block_reader)(
- void * baton,
- const char * data,
- size_t len);
- //------------------------------------------------------------------------------
- // from dirent_uri.h
- static bool
- dirent_is_root(
- const char * dirent,
- apr_size_t len);
- //------------------------------------------------------------------------------
- // from svn_props.h
- static error_t
- neon_get_props_resource(
- neon_resource_t ** rsrc,
- neon_session_t * sess,
- const char * url,
- const ne_propname * which_props,
- bool check_errors,
- apr_pool_t * pool);
- //------------------------------------------------------------------------------
- // from ra_loader.h
- // The RA layer vtable.
- typedef struct vtable_t
- {
- // Return a short description of the RA implementation, as a localized
- // string.
- const char * (*get_description)(void);
- // Return a list of actual URI schemes supported by this implementation.
- // The returned array is NULL-terminated.
- const char * const * (*get_schemes)(apr_pool_t * pool);
- // Implementations of the public API functions.
- // See session_open().
- // All fields in SESSION, except priv, have been initialized by the
- // time this is called. SESSION->priv may be set by this function.
- error_t (*open_session)(session_t * session,
- const char ** corrected_url,
- const char * session_URL,
- const callbacks2_t * callbacks,
- void * callback_baton,
- apr_pool_t * pool);
- // See reparent().
- // URL is guaranteed to have what get_webdav_resource_root() returns as a prefix.
- error_t (*reparent)(session_t * session,
- const char * url,
- apr_pool_t * pool);
- // See get_session_url().
- error_t (*get_session_url)(session_t * session,
- const char ** url,
- apr_pool_t * pool);
- // See get_file().
- error_t (*get_file)(session_t * session,
- const char * path,
- stream_t * stream,
- apr_hash_t ** props,
- apr_pool_t * pool);
- // See get_dir2().
- error_t (*get_dir)(session_t * session,
- apr_hash_t ** dirents,
- const char * path,
- apr_uint32_t dirent_fields,
- apr_pool_t * pool);
- // See check_path().
- error_t (*check_path)(session_t * session,
- const char * path,
- node_kind_t * kind,
- apr_pool_t * pool);
- // See stat().
- error_t (*stat)(session_t * session,
- const char * path,
- dirent_t ** dirent,
- apr_pool_t * pool);
- // See get_webdav_resource_root2().
- error_t (*get_webdav_resource_root)(session_t * session,
- const char ** url,
- apr_pool_t * pool);
- // See has_capability().
- // error_t (*has_capability)(session_t *session,
- // bool *has,
- // const char *capability,
- // apr_pool_t *pool);
- } vtable_t;
- static error_t
- get_path_relative_to_root(
- session_t * session,
- const char ** rel_path,
- const char * url,
- apr_pool_t * pool);
- static error_t
- neon_init(
- const vtable_t ** vtable,
- apr_pool_t * pool);
- //------------------------------------------------------------------------------
- // from svn_ctype.h
- // Table of flags for character classification.
- extern const apr_uint32_t * const ctype_table;
- // Check if c is in the character class described by flags.
- // The flags is a bitwise-or combination of WEBDAV_CTYPE_*
- // constants. Uses #ctype_table.
- #define ctype_test(c, flags) \
- (0 != (ctype_table[(unsigned char)(c)] & (flags)))
- // Basic character classes
- #define WEBDAV_CTYPE_CNTRL 0x0001 //< Control character
- #define WEBDAV_CTYPE_SPACE 0x0002 //< Whitespace
- #define WEBDAV_CTYPE_DIGIT 0x0004 //< Decimal digit
- #define WEBDAV_CTYPE_UPPER 0x0008 //< Uppercase letter
- #define WEBDAV_CTYPE_LOWER 0x0010 //< Lowercase letter
- #define WEBDAV_CTYPE_PUNCT 0x0020 //< Punctuation mark
- #define WEBDAV_CTYPE_XALPHA 0x0040 //< Hexadecimal digits A to F
- #define WEBDAV_CTYPE_ASCII 0x0080 //< ASCII subset*/
- // Derived character classes
- // ASCII letter
- #define WEBDAV_CTYPE_ALPHA (WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_UPPER)
- // ASCII letter or decimal digit
- #define WEBDAV_CTYPE_ALNUM (WEBDAV_CTYPE_ALPHA | WEBDAV_CTYPE_DIGIT)
- // ASCII hexadecimal digit
- #define WEBDAV_CTYPE_XDIGIT (WEBDAV_CTYPE_DIGIT | WEBDAV_CTYPE_XALPHA)
- // Printable ASCII except space
- #define WEBDAV_CTYPE_GRAPH (WEBDAV_CTYPE_PUNCT | WEBDAV_CTYPE_ALNUM)
- // All printable ASCII
- #define WEBDAV_CTYPE_PRINT (WEBDAV_CTYPE_GRAPH | WEBDAV_CTYPE_SPACE)
- // Check if c is an ASCII control character.
- #define ctype_iscntrl(c) ctype_test((c), WEBDAV_CTYPE_CNTRL)
- // Check if c is an ASCII whitespace character.
- #define ctype_isspace(c) ctype_test((c), WEBDAV_CTYPE_SPACE)
- // Check if c is an ASCII digit.
- #define ctype_isdigit(c) ctype_test((c), WEBDAV_CTYPE_DIGIT)
- // Check if c is an ASCII uppercase letter.
- #define ctype_isupper(c) ctype_test((c), WEBDAV_CTYPE_UPPER)
- // Check if c is an ASCII lowercase letter.
- #define ctype_islower(c) ctype_test((c), WEBDAV_CTYPE_LOWER)
- // Check if c is an ASCII punctuation mark.
- #define ctype_ispunct(c) ctype_test((c), WEBDAV_CTYPE_PUNCT)
- // Check if c is an ASCII character.
- #define ctype_isascii(c) ctype_test((c), WEBDAV_CTYPE_ASCII)
- // Check if c is an ASCII letter.
- #define ctype_isalpha(c) ctype_test((c), WEBDAV_CTYPE_ALPHA)
- // Check if c is an ASCII letter or decimal digit.
- #define ctype_isalnum(c) ctype_test((c), WEBDAV_CTYPE_ALNUM)
- // Check if c is an ASCII hexadecimal digit.
- #define ctype_isxdigit(c) ctype_test((c), WEBDAV_CTYPE_XDIGIT)
- // Check if c is an ASCII graphical (visible printable) character.
- #define ctype_isgraph(c) ctype_test((c), WEBDAV_CTYPE_GRAPH)
- // Check if c is an ASCII printable character.
- #define ctype_isprint(c) ctype_test((c), WEBDAV_CTYPE_PRINT)
- // Basic extended character classes
- #define WEBDAV_CTYPE_UTF8LEAD 0x0100 //< UTF-8 multibyte lead byte
- #define WEBDAV_CTYPE_UTF8CONT 0x0200 //< UTF-8 multibyte non-lead byte
- #define WEBDAV_CTYPE_XMLNAME 0x0400
- #define WEBDAV_CTYPE_URISAFE 0x0800
- // Derived extended character classes
- // Part of a UTF-8 multibyte character.
- #define WEBDAV_CTYPE_UTF8MBC (WEBDAV_CTYPE_UTF8LEAD | WEBDAV_CTYPE_UTF8CONT)
- // All valid UTF-8 bytes.
- #define WEBDAV_CTYPE_UTF8 (WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UTF8MBC)
- // Check if c is a UTF-8 multibyte lead byte.
- #define ctype_isutf8lead(c) ctype_test((c), WEBDAV_CTYPE_UTF8LEAD)
- // Check if c is a UTF-8 multibyte continuation (non-lead) byte.
- #define ctype_isutf8cont(c) ctype_test((c), WEBDAV_CTYLE_UTF8CONT)
- // Check if c is part of a UTF-8 multibyte character.
- #define ctype_isutf8mbc(c) ctype_test((c), WEBDAV_CTYPE_UTF8MBC)
- // Check if c is valid in UTF-8.
- #define ctype_isutf8(c) ctype_test((c), WEBDAV_CTYPE_UTF8)
- #define WEBDAV_CTYPE_ASCII_MINUS 45 //< ASCII value of '-'
- #define WEBDAV_CTYPE_ASCII_DOT 46 //< ASCII value of '.'
- #define WEBDAV_CTYPE_ASCII_COLON 58 //< ASCII value of ':'
- #define WEBDAV_CTYPE_ASCII_UNDERSCORE 95 //< ASCII value of '_'
- #define WEBDAV_CTYPE_ASCII_TAB 9 //< ASCII value of a tab
- #define WEBDAV_CTYPE_ASCII_LINEFEED 10 //< ASCII value of a line feed
- #define WEBDAV_CTYPE_ASCII_CARRIAGERETURN 13
- //< ASCII value of a carriage return
- #define WEBDAV_CTYPE_ASCII_DELETE 127
- //< ASCII value of a delete character
- /*
- * Compare two characters a and b, treating case-equivalent
- * unaccented Latin (ASCII subset) letters as equal.
- *
- * Returns in integer greater than, equal to, or less than 0,
- * according to whether a is considered greater than, equal to,
- * or less than b.
- */
- static int
- ctype_casecmp(int a, int b);
- //------------------------------------------------------------------------------
- // from svn_string.c
- static APR_INLINE bool
- string_compare(
- const char * str1,
- const char * str2,
- apr_size_t len1,
- apr_size_t len2)
- {
- // easy way out :)
- if (len1 != len2)
- return FALSE;
- // now the strings must have identical lengths
- if ((memcmp(str1, str2, len1)) == 0)
- return TRUE;
- else
- return FALSE;
- }
- // Our own realloc, since APR doesn't have one. Note: this is a
- // generic realloc for memory pools, *not* for strings.
- static void *
- my_realloc(
- char * data,
- apr_size_t oldsize,
- apr_size_t request,
- apr_pool_t * pool)
- {
- void * new_area = NULL;
- // todo: it's a pity APR doesn't give us this -- sometimes it
- // could realloc the block merely by extending in place, sparing us
- // a memcpy(), but only the pool would know enough to be able to do
- // this. We should add a realloc() to APR if someone hasn't
- // already.
- // malloc new area
- new_area = apr_pcalloc(pool, request);
- // copy data to new area
- memcpy(new_area, data, oldsize);
- // I'm NOT freeing old area here -- cuz we're using pools, ugh.
- // return new area
- return new_area;
- }
- // string functions
- static stringbuf_t *
- stringbuf_create_ensure(
- apr_size_t blocksize,
- apr_pool_t * pool)
- {
- void * mem = NULL;
- stringbuf_t * new_string = NULL;
- // apr_pcalloc will allocate multiples of 8.
- // Thus, we would waste some of that memory if we stuck to the
- // smaller size. Note that this is safe even if apr_pcalloc would
- // use some other alignment or none at all.
- ++blocksize; // + space for '\0'
- blocksize = APR_ALIGN_DEFAULT(blocksize);
- // Allocate memory for string_t and data in one chunk.
- mem = apr_pcalloc(pool, sizeof(*new_string) + blocksize);
- // Initialize header and string
- new_string = static_cast<stringbuf_t *>(mem);
- new_string->data = (char *)mem + sizeof(*new_string);
- new_string->data[0] = '\0';
- new_string->len = 0;
- new_string->blocksize = blocksize;
- new_string->pool = pool;
- return new_string;
- }
- static stringbuf_t *
- stringbuf_ncreate(
- const char * bytes,
- apr_size_t size,
- apr_pool_t * pool)
- {
- stringbuf_t * strbuf = stringbuf_create_ensure(size, pool);
- memcpy(strbuf->data, bytes, size);
- // Null termination is the convention -- even if we suspect the data
- // to be binary, it's not up to us to decide, it's the caller's
- // call. Heck, that's why they call it the caller!
- strbuf->data[size] = '\0';
- strbuf->len = size;
- return strbuf;
- }
- static stringbuf_t *
- stringbuf_create(
- const char * cstring,
- apr_pool_t * pool)
- {
- return stringbuf_ncreate(cstring, strlen(cstring), pool);
- }
- static void
- stringbuf_ensure(
- stringbuf_t * str,
- apr_size_t minimum_size)
- {
- // Keep doubling capacity until have enough.
- if (str->blocksize < minimum_size)
- {
- if (str->blocksize == 0)
- // APR will increase odd allocation sizes to the next
- // multiple for 8, for instance. Take advantage of that
- // knowledge and allow for the extra size to be used.
- str->blocksize = APR_ALIGN_DEFAULT(minimum_size);
- else
- while (str->blocksize < minimum_size)
- {
- // str->blocksize is aligned;
- // doubling it should keep it aligned
- apr_size_t prev_size = str->blocksize;
- str->blocksize *= 2;
- // check for apr_size_t overflow
- if (prev_size > str->blocksize)
- {
- str->blocksize = minimum_size;
- break;
- }
- }
- str->data = (char *) my_realloc(str->data,
- str->len + 1,
- // We need to maintain (and thus copy)
- // the trailing null
- str->blocksize,
- str->pool);
- }
- }
- static void
- stringbuf_set(
- stringbuf_t * str,
- const char * value)
- {
- apr_size_t amt = strlen(value);
- stringbuf_ensure(str, amt + 1);
- memcpy(str->data, value, amt + 1);
- str->len = amt;
- }
- static void
- stringbuf_setempty(
- stringbuf_t * str)
- {
- if (str->len > 0)
- str->data[0] = '\0';
- str->len = 0;
- }
- static bool
- stringbuf_isempty(
- const stringbuf_t * str)
- {
- return (str->len == 0);
- }
- // Return a new string_t object, allocated in POOL, initialized with
- // DATA and SIZE. Do not copy the contents of DATA, just store the pointer.
- // SIZE is the length in bytes of DATA, excluding the required NUL
- // terminator.
- static string_t *
- create_string(
- const char * data,
- apr_size_t size,
- apr_pool_t * pool)
- {
- string_t * new_string;
- new_string = static_cast<string_t *>(apr_pcalloc(pool, sizeof(*new_string)));
- new_string->data = data;
- new_string->len = size;
- return new_string;
- }
- static string_t *
- string_ncreate(
- const char * bytes,
- apr_size_t size,
- apr_pool_t * pool)
- {
- void * mem = NULL;
- char * data = NULL;
- string_t * new_string;
- // Allocate memory for string_t and data in one chunk.
- mem = apr_pcalloc(pool, sizeof(*new_string) + size + 1);
- data = (char *)mem + sizeof(*new_string);
- new_string = static_cast<string_t *>(mem);
- new_string->data = data;
- new_string->len = size;
- memcpy(data, bytes, size);
- // Null termination is the convention -- even if we suspect the data
- // to be binary, it's not up to us to decide, it's the caller's
- // call. Heck, that's why they call it the caller!
- data[size] = '\0';
- return new_string;
- }
- static string_t *
- string_create(
- const char * cstring,
- apr_pool_t * pool)
- {
- return string_ncreate(cstring, strlen(cstring), pool);
- }
- static string_t *
- string_createv(
- apr_pool_t * pool,
- const char * fmt,
- va_list ap)
- {
- char * data = apr_pvsprintf(pool, fmt, ap);
- // wrap an string_t around the new data
- return create_string(data, strlen(data), pool);
- }
- static string_t *
- string_createf(
- apr_pool_t * pool,
- const char * fmt,
- ...)
- {
- string_t * str = NULL;
- va_list ap;
- va_start(ap, fmt);
- str = string_createv(pool, fmt, ap);
- va_end(ap);
- return str;
- }
- static bool
- string_compare(
- const string_t * str1,
- const string_t * str2)
- {
- return
- string_compare(str1->data, str2->data, str1->len, str2->len);
- }
- static void
- stringbuf_appendbytes(
- stringbuf_t * str,
- const char * bytes,
- apr_size_t count)
- {
- apr_size_t total_len = 0;
- void * start_address = NULL;
- total_len = str->len + count; // total size needed
- // +1 for null terminator.
- stringbuf_ensure(str, (total_len + 1));
- // get address 1 byte beyond end of original bytestring
- start_address = (str->data + str->len);
- memcpy(start_address, bytes, count);
- str->len = total_len;
- str->data[str->len] = '\0'; // We don't know if this is binary
- // data or not, but convention is
- // to null-terminate.
- }
- static void
- stringbuf_appendstr(
- stringbuf_t * targetstr,
- const stringbuf_t * appendstr)
- {
- stringbuf_appendbytes(targetstr, appendstr->data, appendstr->len);
- }
- static void
- stringbuf_appendcstr(
- stringbuf_t * targetstr,
- const char * cstr)
- {
- stringbuf_appendbytes(targetstr, cstr, strlen(cstr));
- }
- static error_t
- cstring_strtoi64(
- apr_int64_t * n,
- const char * str,
- apr_int64_t minval,
- apr_int64_t maxval,
- int base)
- {
- apr_int64_t val = 0;
- char * endptr = NULL;
- // We assume errno is thread-safe.
- errno = 0; // APR-0.9 doesn't always set errno
- val = apr_strtoi64(str, &endptr, base);
- if (errno == EINVAL || endptr == str || str[0] == '\0' || *endptr != '\0')
- return error_createf(WEBDAV_ERR_INCORRECT_PARAMS, NULL,
- "Could not convert '%s' into a number",
- str);
- if ((errno == ERANGE && (val == APR_INT64_MIN || val == APR_INT64_MAX)) ||
- val < minval || val > maxval)
- // Mark this for translation when gettext doesn't choke on macros.
- return error_createf(WEBDAV_ERR_INCORRECT_PARAMS, NULL,
- "Number '%s' is out of range "
- "'[%" APR_INT64_T_FMT ", %" APR_INT64_T_FMT "]'",
- str, minval, maxval);
- *n = val;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- cstring_atoi64(
- apr_int64_t * n,
- const char * str)
- {
- return error_trace(cstring_strtoi64(n, str, APR_INT64_MIN,
- APR_INT64_MAX, 10));
- }
- static int
- cstring_casecmp(
- const char * str1,
- const char * str2)
- {
- for (;;)
- {
- const int a = *str1++;
- const int b = *str2++;
- const int cmp = ctype_casecmp(a, b);
- if (cmp || !a || !b)
- return cmp;
- }
- }
- static stringbuf_t *
- create_stringbuf(
- char * data,
- apr_size_t size,
- apr_size_t blocksize,
- apr_pool_t * pool)
- {
- stringbuf_t * new_string;
- new_string = static_cast<stringbuf_t *>(apr_pcalloc(pool, sizeof(*new_string)));
- new_string->data = data;
- new_string->len = size;
- new_string->blocksize = blocksize;
- new_string->pool = pool;
- return new_string;
- }
- static stringbuf_t *
- stringbuf_createv(
- apr_pool_t * pool,
- const char * fmt,
- va_list ap)
- {
- char * data = apr_pvsprintf(pool, fmt, ap);
- apr_size_t size = strlen(data);
- // wrap an stringbuf_t around the new data
- return create_stringbuf(data, size, size + 1, pool);
- }
- static stringbuf_t *
- stringbuf_createf(
- apr_pool_t * pool,
- const char * fmt,
- ...)
- {
- stringbuf_t * str = NULL;
- va_list ap;
- va_start(ap, fmt);
- str = stringbuf_createv(pool, fmt, ap);
- va_end(ap);
- return str;
- }
- static void
- cstring_split_append(
- apr_array_header_t * array,
- const char * input,
- const char * sep_chars,
- bool chop_whitespace,
- apr_pool_t * pool)
- {
- char * last = NULL;
- char * pats = apr_pstrdup(pool, input); // strtok wants non-const data
- char * p = apr_strtok(pats, sep_chars, &last);
- while (p)
- {
- if (chop_whitespace)
- {
- while (ctype_isspace(*p))
- p++;
- {
- char * e = p + (strlen(p) - 1);
- while ((e >= p) && (ctype_isspace(*e)))
- e--;
- *(++e) = '\0';
- }
- }
- if (p[0] != '\0')
- APR_ARRAY_PUSH(array, const char *) = p;
- p = apr_strtok(NULL, sep_chars, &last);
- }
- return;
- }
- static apr_array_header_t *
- cstring_split(
- const char * input,
- const char * sep_chars,
- bool chop_whitespace,
- apr_pool_t * pool)
- {
- apr_array_header_t * a = apr_array_make(pool, 5, sizeof(input));
- cstring_split_append(a, input, sep_chars, chop_whitespace, pool);
- return a;
- }
- //------------------------------------------------------------------------------
- // from ctype.c
- static const apr_uint32_t ctype_table_internal[256] =
- {
- // **** DO NOT EDIT! ****
- // This table was generated by genctype.py, make changes there.
- /* nul */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* soh */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* stx */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* etx */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* eot */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* enq */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* ack */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* bel */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* bs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* ht */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* nl */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* vt */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* np */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* cr */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* so */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* si */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dle */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dc1 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dc2 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dc3 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dc4 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* nak */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* syn */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* etb */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* can */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* em */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* sub */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* esc */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* fs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* gs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* rs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* us */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* sp */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_SPACE,
- /* ! */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* " */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* # */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* $ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* % */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* & */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ' */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ( */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ) */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* * */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* + */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* , */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* - */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* . */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* / */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* 0 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 1 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 2 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 3 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 4 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 5 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 6 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 7 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 8 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 9 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* : */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ; */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* < */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* = */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* > */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ? */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* @ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* A */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* B */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* C */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* D */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* E */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* F */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* G */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* H */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* I */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* J */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* K */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* L */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* M */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* N */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* O */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* P */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* Q */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* R */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* S */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* T */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* U */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* V */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* W */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* X */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* Y */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* Z */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* [ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* \ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ] */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ^ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* _ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ` */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* a */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* b */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* c */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* d */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* e */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* f */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* g */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* h */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* i */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* j */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* k */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* l */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* m */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* n */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* o */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* p */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* q */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* r */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* s */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* t */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* u */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* v */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* w */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* x */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* y */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* z */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* { */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* | */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* } */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ~ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* del */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* x80 */ WEBDAV_CTYPE_UTF8CONT,
- /* x81 */ WEBDAV_CTYPE_UTF8CONT,
- /* x82 */ WEBDAV_CTYPE_UTF8CONT,
- /* x83 */ WEBDAV_CTYPE_UTF8CONT,
- /* x84 */ WEBDAV_CTYPE_UTF8CONT,
- /* x85 */ WEBDAV_CTYPE_UTF8CONT,
- /* x86 */ WEBDAV_CTYPE_UTF8CONT,
- /* x87 */ WEBDAV_CTYPE_UTF8CONT,
- /* x88 */ WEBDAV_CTYPE_UTF8CONT,
- /* x89 */ WEBDAV_CTYPE_UTF8CONT,
- /* x8a */ WEBDAV_CTYPE_UTF8CONT,
- /* x8b */ WEBDAV_CTYPE_UTF8CONT,
- /* x8c */ WEBDAV_CTYPE_UTF8CONT,
- /* x8d */ WEBDAV_CTYPE_UTF8CONT,
- /* x8e */ WEBDAV_CTYPE_UTF8CONT,
- /* x8f */ WEBDAV_CTYPE_UTF8CONT,
- /* x90 */ WEBDAV_CTYPE_UTF8CONT,
- /* x91 */ WEBDAV_CTYPE_UTF8CONT,
- /* x92 */ WEBDAV_CTYPE_UTF8CONT,
- /* x93 */ WEBDAV_CTYPE_UTF8CONT,
- /* x94 */ WEBDAV_CTYPE_UTF8CONT,
- /* x95 */ WEBDAV_CTYPE_UTF8CONT,
- /* x96 */ WEBDAV_CTYPE_UTF8CONT,
- /* x97 */ WEBDAV_CTYPE_UTF8CONT,
- /* x98 */ WEBDAV_CTYPE_UTF8CONT,
- /* x99 */ WEBDAV_CTYPE_UTF8CONT,
- /* x9a */ WEBDAV_CTYPE_UTF8CONT,
- /* x9b */ WEBDAV_CTYPE_UTF8CONT,
- /* x9c */ WEBDAV_CTYPE_UTF8CONT,
- /* x9d */ WEBDAV_CTYPE_UTF8CONT,
- /* x9e */ WEBDAV_CTYPE_UTF8CONT,
- /* x9f */ WEBDAV_CTYPE_UTF8CONT,
- /* xa0 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa1 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa2 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa3 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa4 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa5 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa6 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa7 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa8 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa9 */ WEBDAV_CTYPE_UTF8CONT,
- /* xaa */ WEBDAV_CTYPE_UTF8CONT,
- /* xab */ WEBDAV_CTYPE_UTF8CONT,
- /* xac */ WEBDAV_CTYPE_UTF8CONT,
- /* xad */ WEBDAV_CTYPE_UTF8CONT,
- /* xae */ WEBDAV_CTYPE_UTF8CONT,
- /* xaf */ WEBDAV_CTYPE_UTF8CONT,
- /* xb0 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb1 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb2 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb3 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb4 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb5 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb6 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb7 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb8 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb9 */ WEBDAV_CTYPE_UTF8CONT,
- /* xba */ WEBDAV_CTYPE_UTF8CONT,
- /* xbb */ WEBDAV_CTYPE_UTF8CONT,
- /* xbc */ WEBDAV_CTYPE_UTF8CONT,
- /* xbd */ WEBDAV_CTYPE_UTF8CONT,
- /* xbe */ WEBDAV_CTYPE_UTF8CONT,
- /* xbf */ WEBDAV_CTYPE_UTF8CONT,
- /* xc0 */ 0,
- /* xc1 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc2 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc3 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc4 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc5 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc6 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc7 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc8 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc9 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xca */ WEBDAV_CTYPE_UTF8LEAD,
- /* xcb */ WEBDAV_CTYPE_UTF8LEAD,
- /* xcc */ WEBDAV_CTYPE_UTF8LEAD,
- /* xcd */ WEBDAV_CTYPE_UTF8LEAD,
- /* xce */ WEBDAV_CTYPE_UTF8LEAD,
- /* xcf */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd0 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd1 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd2 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd3 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd4 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd5 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd6 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd7 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd8 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd9 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xda */ WEBDAV_CTYPE_UTF8LEAD,
- /* xdb */ WEBDAV_CTYPE_UTF8LEAD,
- /* xdc */ WEBDAV_CTYPE_UTF8LEAD,
- /* xdd */ WEBDAV_CTYPE_UTF8LEAD,
- /* xde */ WEBDAV_CTYPE_UTF8LEAD,
- /* xdf */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe0 */ 0,
- /* xe1 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe2 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe3 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe4 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe5 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe6 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe7 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe8 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe9 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xea */ WEBDAV_CTYPE_UTF8LEAD,
- /* xeb */ WEBDAV_CTYPE_UTF8LEAD,
- /* xec */ WEBDAV_CTYPE_UTF8LEAD,
- /* xed */ WEBDAV_CTYPE_UTF8LEAD,
- /* xee */ WEBDAV_CTYPE_UTF8LEAD,
- /* xef */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf0 */ 0,
- /* xf1 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf2 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf3 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf4 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf5 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf6 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf7 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf8 */ 0,
- /* xf9 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xfa */ WEBDAV_CTYPE_UTF8LEAD,
- /* xfb */ WEBDAV_CTYPE_UTF8LEAD,
- /* xfc */ 0,
- /* xfd */ WEBDAV_CTYPE_UTF8LEAD,
- /* xfe */ 0,
- /* xff */ 0
- };
- const apr_uint32_t * const ctype_table = ctype_table_internal;
- static const unsigned char casefold_table[256] =
- {
- // Identity, except {97:122} => {65:90}
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127,
- 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
- 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
- 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
- 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
- 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
- 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
- 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
- };
- static int
- ctype_casecmp(int a, int b)
- {
- const int A = casefold_table[(unsigned char)a];
- const int B = casefold_table[(unsigned char)b];
- return A - B;
- }
- //------------------------------------------------------------------------------
- // from svn_pool.c
- // Pool allocation handler which just aborts, since we aren't generally
- // prepared to deal with out-of-memory errors.
- static int
- abort_on_pool_failure(int retcode)
- {
- // Don't translate this string! It requires memory allocation to do so!
- // And we don't have any of it...
- printf("Out of memory - terminating application.\n");
- abort();
- }
- static apr_pool_t *
- pool_create_ex(
- apr_pool_t * parent_pool,
- apr_allocator_t * allocator)
- {
- apr_pool_t * pool;
- apr_pool_create_ex(&pool, parent_pool, abort_on_pool_failure, allocator);
- return pool;
- }
- //------------------------------------------------------------------------------
- // from time.c
- #define OLD_TIMESTAMP_FORMAT \
- "%3s %d %3s %d %02d:%02d:%02d.%06d (day %03d, dst %d, gmt_off %06d)"
- static apr_size_t
- find_matching_string(
- char * str,
- apr_size_t size,
- const char strings[][4])
- {
- for (apr_size_t i = 0; i < size; i++)
- if (strings[i] && (strcmp(str, strings[i]) == 0))
- return i;
- return (apr_size_t)-1;
- }
- static error_t
- time_from_cstring(
- apr_time_t * when,
- const char * data,
- apr_pool_t * pool)
- {
- apr_time_exp_t exploded_time;
- apr_status_t apr_err = 0;
- char wday[4] = {0}, month[4] = {0};
- char * c = NULL;
- // Open-code parsing of the new timestamp format, as this
- // is a hot path for reading the entries file. This format looks
- // like: "2001-08-31T04:24:14.966996Z"
- exploded_time.tm_year = strtol(data, &c, 10);
- if (*c++ != '-') goto fail;
- exploded_time.tm_mon = strtol(c, &c, 10);
- if (*c++ != '-') goto fail;
- exploded_time.tm_mday = strtol(c, &c, 10);
- if (*c++ != 'T') goto fail;
- exploded_time.tm_hour = strtol(c, &c, 10);
- if (*c++ != ':') goto fail;
- exploded_time.tm_min = strtol(c, &c, 10);
- if (*c++ != ':') goto fail;
- exploded_time.tm_sec = strtol(c, &c, 10);
- if (*c != 'Z')
- {
- if (*c++ != '.') goto fail;
- exploded_time.tm_usec = strtol(c, &c, 10);
- if (*c++ != 'Z') goto fail;
- }
- exploded_time.tm_year -= 1900;
- exploded_time.tm_mon -= 1;
- exploded_time.tm_wday = 0;
- exploded_time.tm_yday = 0;
- exploded_time.tm_isdst = 0;
- exploded_time.tm_gmtoff = 0;
- apr_err = apr_time_exp_gmt_get(when, &exploded_time);
- if (apr_err == APR_SUCCESS)
- return WEBDAV_NO_ERROR;
- return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- fail:
- // 2012-09-11T14:18:40+07:00
- char gmt_shift = 0;
- int gmt_hour = 0;
- int gmt_min = 0;
- if (sscanf(data,
- "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
- &exploded_time.tm_year,
- &exploded_time.tm_mon,
- &exploded_time.tm_mday,
- &exploded_time.tm_hour,
- &exploded_time.tm_min,
- &exploded_time.tm_sec,
- &gmt_shift,
- &gmt_hour,
- &gmt_min) == 9)
- {
- exploded_time.tm_year -= 1900;
- exploded_time.tm_mon -= 1;
- exploded_time.tm_wday = 0;
- exploded_time.tm_yday = 0;
- exploded_time.tm_isdst = 0;
- exploded_time.tm_gmtoff = (gmt_shift == '-' ? -1 : 1) * gmt_hour * SecsPerHour + gmt_min * SecsPerMin;
- exploded_time.tm_usec = 0;
- apr_err = apr_time_exp_gmt_get(when, &exploded_time);
- if (apr_err != APR_SUCCESS)
- return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- return WEBDAV_NO_ERROR;
- }
- // 2012-09-11T03:56:20
- if (sscanf(data,
- "%04d-%02d-%02dT%02d:%02d:%02d",
- &exploded_time.tm_year,
- &exploded_time.tm_mon,
- &exploded_time.tm_mday,
- &exploded_time.tm_hour,
- &exploded_time.tm_min,
- &exploded_time.tm_sec) == 6)
- {
- exploded_time.tm_year -= 1900;
- exploded_time.tm_mon -= 1;
- exploded_time.tm_wday = 0;
- exploded_time.tm_yday = 0;
- exploded_time.tm_isdst = 0;
- exploded_time.tm_gmtoff = 0;
- exploded_time.tm_usec = 0;
- apr_err = apr_time_exp_gmt_get(when, &exploded_time);
- if (apr_err != APR_SUCCESS)
- return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- return WEBDAV_NO_ERROR;
- }
- // Try the compatibility option. This does not need to be fast,
- // as this format is no longer generated and the client will convert
- // an old-format entries file the first time it reads it.
- if (sscanf(data,
- OLD_TIMESTAMP_FORMAT,
- wday,
- &exploded_time.tm_mday,
- month,
- &exploded_time.tm_year,
- &exploded_time.tm_hour,
- &exploded_time.tm_min,
- &exploded_time.tm_sec,
- &exploded_time.tm_usec,
- &exploded_time.tm_yday,
- &exploded_time.tm_isdst,
- &exploded_time.tm_gmtoff) == 11)
- {
- exploded_time.tm_year -= 1900;
- exploded_time.tm_yday -= 1;
- // Using hard coded limits for the arrays - they are going away
- // soon in any case.
- exploded_time.tm_wday = (apr_int32_t)find_matching_string(wday, 7, apr_day_snames);
- exploded_time.tm_mon = (apr_int32_t)find_matching_string(month, 12, apr_month_snames);
- apr_err = apr_time_exp_gmt_get(when, &exploded_time);
- if (apr_err != APR_SUCCESS)
- return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- return WEBDAV_NO_ERROR;
- }
- // Timestamp is something we do not recognize.
- // return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- *when = apr_time_now();
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from path.c
- // TRUE if s is the canonical empty path, FALSE otherwise
- #define WEBDAV_PATH_IS_EMPTY(s) ((s)[0] == '\0')
- // TRUE if s,n is the platform's empty path ("."), FALSE otherwise. Can
- // this be changed? Well, the path library will work, not so sure about
- // the OS!
- #define WEBDAV_PATH_IS_PLATFORM_EMPTY(s,n) ((n) == 1 && (s)[0] == '.')
- /* Here is the BNF for path components in a URI. "pchar" is a
- character in a path component.
- pchar = unreserved | escaped |
- ":" | "@" | "&" | "=" | "+" | "$" | ","
- unreserved = alphanum | mark
- mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
- Note that "escaped" doesn't really apply to what users can put in
- their paths, so that really means the set of characters is:
- alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | ","
- */
- static const char uri_char_validity[256] =
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
- // 64
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
- // 128
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // 192
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- };
- // URI-encode each character c in PATH for which TABLE[c] is 0.
- // If no encoding was needed, return PATH, else return a new string allocated
- // in POOL.
- static const char *
- uri_escape(
- const char * path,
- const char table[],
- apr_pool_t * pool)
- {
- stringbuf_t * retstr = NULL;
- size_t i = 0, copied = 0;
- int c = 0;
- retstr = stringbuf_create_ensure(strlen(path), pool);
- for (i = 0; path[i]; i++)
- {
- c = (unsigned char)path[i];
- if (table[c])
- continue;
- // If we got here, we're looking at a character that isn't
- // supported by the (or at least, our) URI encoding scheme. We
- // need to escape this character.
- // First things first, copy all the good stuff that we haven't
- // yet copied into our output buffer.
- if (i - copied)
- stringbuf_appendbytes(retstr, path + copied,
- i - copied);
- // Now, write in our escaped character, consisting of the
- // '%' and two digits. We cast the C to unsigned char here because
- // the 'X' format character will be tempted to treat it as an unsigned
- // int...which causes problem when messing with 0x80-0xFF chars.
- // We also need space for a null as apr_snprintf will write one.
- stringbuf_ensure(retstr, retstr->len + 4);
- apr_snprintf(retstr->data + retstr->len, 4, "%%%02X", (unsigned char)c);
- retstr->len += 3;
- // Finally, update our copy counter.
- copied = i + 1;
- }
- // If we didn't encode anything, we don't need to duplicate the string.
- if (retstr->len == 0)
- return path;
- // Anything left to copy?
- if (i - copied)
- stringbuf_appendbytes(retstr, path + copied, i - copied);
- // retstr is null-terminated either by apr_snprintf or the stringbuf
- // functions.
- return retstr->data;
- }
- static const char *
- path_uri_decode(
- const char * path,
- apr_pool_t * pool)
- {
- stringbuf_t * retstr = NULL;
- size_t i = 0;
- bool query_start = FALSE;
- // avoid repeated realloc
- retstr = stringbuf_create_ensure(strlen(path) + 1, pool);
- retstr->len = 0;
- for (i = 0; path[i]; i++)
- {
- char c = path[i];
- if (c == '?')
- {
- // Mark the start of the query string, if it exists.
- query_start = TRUE;
- }
- else if (c == '+' && query_start)
- {
- // Only do this if we are into the query string.
- // RFC 2396, section 3.3
- c = ' ';
- }
- else if (c == '%' && ctype_isxdigit(path[i + 1]) && ctype_isxdigit(path[i+2]))
- {
- char digitz[3];
- digitz[0] = path[++i];
- digitz[1] = path[++i];
- digitz[2] = '\0';
- c = (char)(strtol(digitz, NULL, 16));
- }
- retstr->data[retstr->len++] = c;
- }
- // Null-terminate this bad-boy.
- retstr->data[retstr->len] = 0;
- return retstr->data;
- }
- static const char *
- path_uri_encode(
- const char * path,
- apr_pool_t * pool)
- {
- const char * ret = uri_escape(path, uri_char_validity, pool);
- // Our interface guarantees a copy.
- if (ret == path)
- return apr_pstrdup(pool, path);
- else
- return ret;
- }
- static char *
- path_join(
- const char * base,
- const char * component,
- apr_pool_t * pool)
- {
- apr_size_t blen = strlen(base);
- apr_size_t clen = strlen(component);
- char * path = NULL;
- // assert(path_is_canonical(base, pool));
- // assert(path_is_canonical(component, pool));
- // If the component is absolute, then return it.
- if (*component == '/')
- return (char *)apr_pmemdup(pool, component, clen + 1);
- // If either is empty return the other
- if (WEBDAV_PATH_IS_EMPTY(base))
- return (char *)apr_pmemdup(pool, component, clen + 1);
- if (WEBDAV_PATH_IS_EMPTY(component))
- return (char *)apr_pmemdup(pool, base, blen + 1);
- if ((blen == 1) && (base[0] == '/'))
- blen = 0; // Ignore base, just return separator + component
- // Construct the new, combined path.
- path = (char *)apr_pcalloc(pool, blen + 1 + clen + 1);
- memcpy(path, base, blen);
- path[blen] = '/';
- memcpy(path + blen + 1, component, clen + 1);
- return path;
- }
- static const char *
- path_url_add_component2(
- const char * url,
- const char * component,
- apr_pool_t * pool)
- {
- // = path_uri_encode() but without always copying
- component = uri_escape(component, uri_char_validity, pool);
- return path_join(url, component, pool);
- }
- // Get APR's internal path encoding.
- static error_t
- get_path_encoding(
- bool * path_is_utf8,
- apr_pool_t * pool)
- {
- apr_status_t apr_err = 0;
- int encoding_style = 0;
- apr_err = apr_filepath_encoding(&encoding_style, pool);
- if (apr_err)
- return error_wrap_apr(apr_err,
- "Can't determine the native path encoding");
- // What to do about APR_FILEPATH_ENCODING_UNKNOWN?
- // Well, for now we'll just punt to the utf_ functions;
- // those will at least do the ASCII-subset check.
- *path_is_utf8 = (encoding_style == APR_FILEPATH_ENCODING_UTF8);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- path_cstring_to_utf8(
- const char ** path_utf8,
- const char * path_apr,
- apr_pool_t * pool)
- {
- bool path_is_utf8 = FALSE;
- WEBDAV_ERR(get_path_encoding(&path_is_utf8, pool));
- if (path_is_utf8)
- {
- *path_utf8 = apr_pstrdup(pool, path_apr);
- return WEBDAV_NO_ERROR;
- }
- else
- return utf_cstring_to_utf8(path_utf8, path_apr, pool);
- }
- static apr_size_t
- path_component_count(
- const char * path)
- {
- if (!path) return 0;
- apr_size_t count = 0;
- while (*path)
- {
- const char * start;
- while (*path == '/')
- ++path;
- start = path;
- while (*path && (*path != '/'))
- ++path;
- if (path != start)
- ++count;
- }
- return count;
- }
- // Return the length of substring necessary to encompass the entire
- // previous path segment in PATH, which should be a LEN byte string.
- // A trailing slash will not be included in the returned length except
- // in the case in which PATH is absolute and there are no more
- // previous segments.
- static apr_size_t
- previous_segment(
- const char * path,
- apr_size_t len)
- {
- if (len == 0)
- return 0;
- while ((len > 0) && (path[--len] != '/'))
- ;
- if ((len == 0) && (path[0] == '/'))
- return 1;
- else
- return len;
- }
- static void
- path_remove_component(
- stringbuf_t * path)
- {
- path->len = previous_segment(path->data, path->len);
- path->data[path->len] = '\0';
- }
- static void
- path_remove_components(
- stringbuf_t * path,
- apr_size_t n)
- {
- while (n > 0)
- {
- path_remove_component(path);
- n--;
- }
- }
- static error_t
- path_cstring_from_utf8(
- const char ** path_apr,
- const char * path_utf8,
- apr_pool_t * pool)
- {
- bool path_is_utf8 = FALSE;
- WEBDAV_ERR(get_path_encoding(&path_is_utf8, pool));
- if (path_is_utf8)
- {
- *path_apr = apr_pstrdup(pool, path_utf8);
- return WEBDAV_NO_ERROR;
- }
- else
- return utf_cstring_from_utf8(path_apr, path_utf8, pool);
- }
- static bool
- path_is_backpath_present(
- const char * path)
- {
- size_t len;
- // 0 and 1-length paths do not have a backpath
- if ((path[0] == '\0') || (path[1] == '\0'))
- return FALSE;
- // Handle ".." or a leading "../"
- if ((path[0] == '.') && (path[1] == '.') && ((path[2] == '\0') || (path[2] == '/')))
- return TRUE;
- // Paths of length 2 (at this point) have no backpath present.
- if (path[2] == '\0')
- return FALSE;
- // If any segment is "..", then a backpath is present.
- if (strstr(path, "/../") != NULL)
- return TRUE;
- // Does the path end in "/.." ?
- len = strlen(path);
- return (path[len - 3] == '/') && (path[len - 2] == '.') && (path[len - 1] == '.');
- }
- //------------------------------------------------------------------------------
- // from svn_client.h
- typedef error_t (*client_list_func_t)(
- void * baton,
- const char * path,
- const dirent_t * dirent,
- const char * abs_path,
- apr_pool_t * pool);
- typedef struct client_ctx_t
- {
- auth_baton_t * auth_baton;
- cancel_func_t cancel_func;
- void * cancel_baton;
- progress_notify_func_t progress_func;
- void * progress_baton;
- const char * client_name;
- } client_ctx_t;
- //------------------------------------------------------------------------------
- // from win32_xlate.c
- static apr_status_t
- subr_win32_xlate_to_stringbuf(// win32_xlate_t *handle,
- const char * src_data,
- apr_size_t src_length,
- stringbuf_t ** dest,
- apr_pool_t * pool)
- {
- WCHAR * wide_str = NULL;
- int retval = 0, wide_size = 0;
- if (src_length == 0)
- {
- *dest = stringbuf_create("", pool);
- return APR_SUCCESS;
- }
- int from_page_id = CP_ACP;
- retval = MultiByteToWideChar(from_page_id, // CP_UTF8, // handle->from_page_id,
- 0, src_data, (int)src_length, NULL, 0);
- if (retval == 0)
- return apr_get_os_error();
- wide_size = retval;
- // Allocate temporary buffer for small strings on stack instead of heap.
- if (wide_size <= MAX_PATH)
- {
- wide_str = static_cast<WCHAR *>(alloca(wide_size * sizeof(WCHAR)));
- }
- else
- {
- wide_str = static_cast<WCHAR *>(apr_pcalloc(pool, wide_size * sizeof(WCHAR)));
- }
- retval = MultiByteToWideChar(from_page_id, // handle->from_page_id,
- 0, src_data, (int)src_length, wide_str, wide_size);
- if (retval == 0)
- return apr_get_os_error();
- int to_page_id = CP_UTF8;
- retval = WideCharToMultiByte(to_page_id, // handle->to_page_id,
- 0, wide_str, wide_size, NULL, 0, NULL, NULL);
- if (retval == 0)
- return apr_get_os_error();
- // Ensure that buffer is enough to hold result string and termination
- // character.
- *dest = stringbuf_create_ensure(retval + 1, pool);
- (*dest)->len = retval;
- retval = WideCharToMultiByte(to_page_id, // handle->to_page_id,
- 0, wide_str, wide_size, (*dest)->data, (int)(*dest)->len, NULL, NULL);
- if (retval == 0)
- return apr_get_os_error();
- (*dest)->len = retval;
- return APR_SUCCESS;
- }
- static apr_status_t
- utf8_to_unicode(
- WCHAR ** retstr,
- const char * srcstr,
- apr_pool_t * pool)
- {
- /*apr_size_t retlen = 0;
- apr_size_t srcremains = strlen(srcstr) + 1;
- *retstr = static_cast<WCHAR *>(apr_pcalloc(pool, srcremains * 4));
- apr_status_t rv;
- if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, *retstr, &retlen)) {
- return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
- }
- if (srcremains) {
- return APR_ENAMETOOLONG;
- }*/
- WCHAR * wide_str = NULL;
- int retval = 0, wide_size = 0;
- apr_size_t src_length = strlen(srcstr);
- if (src_length == 0)
- {
- *retstr = L"";
- return APR_SUCCESS;
- }
- retval = MultiByteToWideChar(CP_UTF8, // handle->from_page_id,
- 0, srcstr, (int)src_length, NULL, 0);
- if (retval == 0)
- return apr_get_os_error();
- wide_size = retval;
- wide_str = static_cast<WCHAR *>(apr_pcalloc(pool, (wide_size + 1) * sizeof(WCHAR)));
- retval = MultiByteToWideChar(CP_UTF8, // handle->from_page_id,
- 0, srcstr, (int)src_length, wide_str, wide_size);
- if (retval == 0)
- return apr_get_os_error();
- *retstr = wide_str;
- (*retstr)[wide_size] = L'\0';
- return APR_SUCCESS;
- }
- //------------------------------------------------------------------------------
- // from utf.c
- // Verify that the sequence DATA of length LEN is valid UTF-8.
- // If it is not, return an error with code APR_EINVAL.
- static error_t
- check_utf8(
- const char * data,
- apr_size_t len,
- apr_pool_t * pool)
- {
- // TODO: if (!utf_is_valid(data, len)))
- // return invalid_utf8(data, len, pool);
- return WEBDAV_NO_ERROR;
- }
- // Convert SRC_LENGTH bytes of SRC_DATA in NODE->handle, store the result
- // in *DEST, which is allocated in POOL.
- static error_t
- convert_to_stringbuf(// xlate_handle_node_t *node,
- const char * src_data,
- apr_size_t src_length,
- stringbuf_t ** dest,
- apr_pool_t * pool)
- {
- apr_status_t apr_err = 0;
- apr_err = subr_win32_xlate_to_stringbuf(// (win32_xlate_t *) node->handle,
- src_data, src_length,
- dest, pool);
- // If we exited the loop with an error, return the error.
- if (apr_err)
- {
- const char * errstr = NULL;
- error_t err = 0;
- // Can't use error_wrap_apr here because it calls functions in
- // this file, leading to infinite recursion.
- errstr = apr_psprintf(pool, "Can't convert string"); // from native encoding to '%s':"),
- err = error_create(apr_err, NULL, "");
- return error_create(apr_err, &err, errstr);
- }
- // Else, exited due to success. Trim the result buffer down to the
- // right length.
- (*dest)->data[(*dest)->len] = '\0';
- return WEBDAV_NO_ERROR;
- }
- // Common implementation for utf_cstring_to_utf8,
- // utf_cstring_to_utf8_ex, utf_cstring_from_utf8 and
- // utf_cstring_from_utf8_ex. Convert SRC to DEST using NODE->handle as
- // the translator and allocating from POOL.
- static error_t
- convert_cstring(
- const char ** dest,
- const char * src,
- apr_pool_t * pool)
- {
- stringbuf_t * destbuf;
- WEBDAV_ERR(convert_to_stringbuf(// node,
- src, strlen(src), &destbuf, pool));
- *dest = destbuf->data;
- return WEBDAV_NO_ERROR;
- }
- // Verify that the NULL terminated sequence DATA is valid UTF-8.
- // If it is not, return an error with code APR_EINVAL.
- static error_t
- check_cstring_utf8(
- const char * data,
- apr_pool_t * pool)
- {
- // TODO: if (!utf_cstring_is_valid(data))
- // return invalid_utf8(data, strlen(data), pool);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- utf_cstring_to_utf8(
- const char ** dest,
- const char * src,
- apr_pool_t * pool)
- {
- // TODO: implement
- error_t err = convert_cstring(dest, src, // node,
- pool);
- WEBDAV_ERR(err);
- return check_cstring_utf8(*dest, pool);
- }
- static error_t
- utf_cstring_from_utf8(
- const char ** dest,
- const char * src,
- apr_pool_t * pool)
- {
- WEBDAV_ERR(check_utf8(src, strlen(src), pool));
- error_t err = convert_cstring(dest, src, pool);
- return err;
- }
- //------------------------------------------------------------------------------
- // from xml.c
- static const char *
- xml_get_attr_value(
- const char * name,
- const char ** atts)
- {
- while (atts && (*atts))
- {
- if (strcmp(atts[0], name) == 0)
- return atts[1];
- else
- atts += 2; // continue looping
- }
- // Else no such attribute name seen.
- return NULL;
- }
- //------------------------------------------------------------------------------
- // from apr_base64.c
- static const char basis_64[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- // This is the same as apr_base64_encode() except on EBCDIC machines, where
- // the conversion of the input to ascii is left out.
- static int
- apr_base64_encode_binary(
- char * encoded,
- const unsigned char * string,
- int len)
- {
- int i;
- char * p;
- p = encoded;
- for (i = 0; i < len - 2; i += 3)
- {
- *p++ = basis_64[(string[i] >> 2) & 0x3F];
- *p++ = basis_64[((string[i] & 0x3) << 4) |
- ((int)(string[i + 1] & 0xF0) >> 4)];
- *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
- ((int)(string[i + 2] & 0xC0) >> 6)];
- *p++ = basis_64[string[i + 2] & 0x3F];
- }
- if (i < len)
- {
- *p++ = basis_64[(string[i] >> 2) & 0x3F];
- if (i == (len - 1))
- {
- *p++ = basis_64[((string[i] & 0x3) << 4)];
- *p++ = '=';
- }
- else
- {
- *p++ = basis_64[((string[i] & 0x3) << 4) |
- ((int)(string[i + 1] & 0xF0) >> 4)];
- *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
- }
- *p++ = '=';
- }
- *p++ = '\0';
- return (int)(p - encoded);
- }
- static int
- apr_base64_encode(
- char * encoded,
- const char * string,
- int len)
- {
- return apr_base64_encode_binary(encoded, (const unsigned char *) string, len);
- }
- static int
- apr_base64_encode_len(int len)
- {
- return ((len + 2) / 3 * 4) + 1;
- }
- // aaaack but it's fast and const should make it shared text page.
- static const unsigned char pr2six[256] =
- {
- // ASCII table
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
- 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
- 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
- };
- static int
- apr_base64_decode_len(
- const char * bufcoded)
- {
- int nbytesdecoded;
- register const unsigned char * bufin;
- register apr_size_t nprbytes;
- bufin = (const unsigned char *) bufcoded;
- while (pr2six[*(bufin++)] <= 63);
- nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
- nbytesdecoded = (((int)nprbytes + 3) / 4) * 3;
- return nbytesdecoded + 1;
- }
- // This is the same as apr_base64_decode() except on EBCDIC machines, where
- // the conversion of the output to ebcdic is left out.
- static int
- apr_base64_decode_binary(
- unsigned char * bufplain,
- const char * bufcoded)
- {
- int nbytesdecoded;
- register const unsigned char * bufin;
- register unsigned char * bufout;
- register apr_size_t nprbytes;
- bufin = (const unsigned char *) bufcoded;
- while (pr2six[*(bufin++)] <= 63);
- nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
- nbytesdecoded = (((int)nprbytes + 3) / 4) * 3;
- bufout = (unsigned char *) bufplain;
- bufin = (const unsigned char *) bufcoded;
- while (nprbytes > 4)
- {
- *(bufout++) =
- (unsigned char)((pr2six[*bufin] << 2) | (pr2six[bufin[1]] >> 4));
- *(bufout++) =
- (unsigned char)((pr2six[bufin[1]] << 4) | (pr2six[bufin[2]] >> 2));
- *(bufout++) =
- (unsigned char)((pr2six[bufin[2]] << 6) | pr2six[bufin[3]]);
- bufin += 4;
- nprbytes -= 4;
- }
- // Note: (nprbytes == 1) would be an error, so just ignore that case
- if (nprbytes > 1)
- {
- *(bufout++) =
- (unsigned char)((pr2six[*bufin] << 2) | (pr2six[bufin[1]] >> 4));
- }
- if (nprbytes > 2)
- {
- *(bufout++) =
- (unsigned char)((pr2six[bufin[1]] << 4) | (pr2six[bufin[2]] >> 2));
- }
- if (nprbytes > 3)
- {
- *(bufout++) =
- (unsigned char)((pr2six[bufin[2]] << 6) | pr2six[bufin[3]]);
- }
- nbytesdecoded -= (4 - (int)nprbytes) & 3;
- return nbytesdecoded;
- }
- static int
- apr_base64_decode(
- char * bufplain,
- const char * bufcoded)
- {
- int len = apr_base64_decode_binary((unsigned char *) bufplain, bufcoded);
- bufplain[len] = '\0';
- return len;
- }
- //---------------------------------------------------------------------------
- // from user.c
- // Get the current user's name from the OS
- static const char *
- get_os_username(
- apr_pool_t * pool)
- {
- #if APR_HAS_USER
- char * username;
- apr_uid_t uid;
- apr_gid_t gid;
- if (apr_uid_current(&uid, &gid, pool) == APR_SUCCESS &&
- apr_uid_name_get(&username, uid, pool) == APR_SUCCESS)
- return username;
- #endif
- return NULL;
- }
- // Return a UTF8 version of STR, or NULL on error.
- // Use POOL for any necessary allocation.
- static const char *
- utf8_or_nothing(
- const char * str,
- apr_pool_t * pool)
- {
- if (str)
- {
- const char * utf8_str;
- error_t err = utf_cstring_to_utf8(&utf8_str, str, pool);
- if (!err)
- return utf8_str;
- error_clear(&err);
- }
- return NULL;
- }
- static const char *
- user_get_name(
- apr_pool_t * pool)
- {
- const char * username = get_os_username(pool);
- return utf8_or_nothing(username, pool);
- }
- //---------------------------------------------------------------------------
- // from sorts.c
- typedef struct sort_item_t
- {
- const void * key;
- apr_ssize_t klen;
- void * value;
- } sort_item_t;
- static int
- sort_compare_items_lexically(
- const sort_item_t * a,
- const sort_item_t * b)
- {
- // Compare bytes of a's key and b's key up to the common length.
- apr_size_t len = (a->klen < b->klen) ? a->klen : b->klen;
- int val = memcmp(a->key, b->key, len);
- if (val != 0)
- return val;
- // They match up until one of them ends; whichever is longer is greater.
- return (a->klen < b->klen) ? -1 : (a->klen > b->klen) ? 1 : 0;
- }
- static apr_array_header_t *
- sort_hash(apr_hash_t * ht,
- int (*comparison_func)(const sort_item_t *,
- const sort_item_t *),
- apr_pool_t * pool)
- {
- apr_array_header_t * ary = NULL;
- bool sorted = FALSE;
- sort_item_t * prev_item = NULL;
- // allocate an array with enough elements to hold all the keys.
- ary = apr_array_make(pool, apr_hash_count(ht), sizeof(sort_item_t));
- // loop over hash table and push all keys into the array
- sorted = TRUE;
- prev_item = NULL;
- for (apr_hash_index_t * hi = apr_hash_first(pool, ht); hi;
- hi = apr_hash_next(hi))
- {
- sort_item_t * item = static_cast<sort_item_t *>(apr_array_push(ary));
- apr_hash_this(hi, &item->key, &item->klen, &item->value);
- if (prev_item == NULL)
- {
- prev_item = item;
- continue;
- }
- if (sorted)
- {
- sorted = (comparison_func(prev_item, item) < 0);
- prev_item = item;
- }
- }
- // quicksort the array if it isn't already sorted.
- if (!sorted)
- qsort(ary->elts, ary->nelts, ary->elt_size,
- (int ( *)(const void *, const void *))comparison_func);
- return ary;
- }
- //---------------------------------------------------------------------------
- // from svn_config.h
- #define WEBDAV_CONFIG_TRUE "TRUE"
- #define WEBDAV_CONFIG_FALSE "FALSE"
- #define WEBDAV_CONFIG_ASK "ASK"
- // Default values for some options. Should be passed as default values
- // to config_get and friends, instead of hard-coding the defaults in
- // multiple places.
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS TRUE
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS WEBDAV_CONFIG_ASK
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS TRUE
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP TRUE
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
- WEBDAV_CONFIG_ASK
- //---------------------------------------------------------------------------
- // from svn_auth.h
- // Certificate is not yet valid.
- #define WEBDAV_AUTH_SSL_NOTYETVALID 0x00000001
- // Certificate has expired.
- #define WEBDAV_AUTH_SSL_EXPIRED 0x00000002
- // Certificate's CN (hostname) does not match the remote hostname.
- #define WEBDAV_AUTH_SSL_CNMISMATCH 0x00000004
- // Certificate authority is unknown (i.e. not trusted)
- #define WEBDAV_AUTH_SSL_UNKNOWNCA 0x00000008
- // Other failure. This can happen if neon has introduced a new
- // failure bit that we do not handle yet.
- #define WEBDAV_AUTH_SSL_OTHER 0x40000000
- #define AUTH_CRED_SSL_CLIENT_CERT_PW "ssl.client-passphrase"
- #define AUTH_CRED_SSL_CLIENT_CERT "ssl.client-cert"
- // The auth-hash prefix indicating that the parameter is global.
- #define AUTH_PARAM_PREFIX "webdav:auth:"
- // The following property is for SSL server cert providers. This
- // provides a pointer to an apr_uint32_t containing the failures
- // detected by the certificate validator.
- #define AUTH_PARAM_SSL_SERVER_FAILURES AUTH_PARAM_PREFIX \
- "ssl:failures"
- // The following property is for SSL server cert providers. This
- // provides the cert info (auth_ssl_server_cert_info_t).
- #define AUTH_PARAM_SSL_SERVER_CERT_INFO AUTH_PARAM_PREFIX \
- "ssl:cert-info"
- #define AUTH_CRED_SSL_SERVER_TRUST "webdav.ssl.server"
- #define AUTH_CRED_SIMPLE "webdav.simple"
- #define WEBDAV_AUTH_CRED_USERNAME "webdav.username"
- #define WEBDAV_AUTH_PARAM_DEFAULT_USERNAME AUTH_PARAM_PREFIX "username"
- #define WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD AUTH_PARAM_PREFIX "password"
- #define WEBDAV_AUTH_PARAM_NON_INTERACTIVE AUTH_PARAM_PREFIX "non-interactive"
- #define WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS AUTH_PARAM_PREFIX \
- "dont-store-passwords"
- #define WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS AUTH_PARAM_PREFIX \
- "store-plaintext-passwords"
- #define WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP \
- AUTH_PARAM_PREFIX "dont-store-ssl-client-cert-pp"
- #define WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
- AUTH_PARAM_PREFIX "store-ssl-client-cert-pp-plaintext"
- #define WEBDAV_AUTH_PARAM_NO_AUTH_CACHE AUTH_PARAM_PREFIX "no-auth-cache"
- #define WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE "simple"
- #define WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE "wincrypt"
- // This effectively defines a single table. Every provider in this
- // array returns the same kind of credentials.
- typedef struct provider_set_t
- {
- // ordered array of auth_provider_object_t
- apr_array_header_t * providers;
- } provider_set_t;
- // Abstracted iteration baton
- struct auth_iterstate_t
- {
- provider_set_t * table; // the table being searched
- int provider_idx; // the current provider (row)
- bool got_first; // did we get the provider's first creds?
- void * provider_iter_baton; // the provider's own iteration context
- const char * realmstring; // The original realmstring passed in
- const char * cache_key; // key to use in auth_baton's creds_cache
- auth_baton_t * auth_baton; // the original auth_baton.
- };
- // The main auth baton.
- typedef struct auth_baton_t
- {
- // a collection of tables. maps cred_kind -> provider_set
- apr_hash_t * tables;
- // the pool I'm allocated in.
- apr_pool_t * pool;
- // run-time parameters needed by providers.
- apr_hash_t * parameters;
- // run-time credentials cache.
- apr_hash_t * creds_cache;
- } auth_baton_t;
- // The main authentication "provider" vtable.
- typedef struct auth_provider_t
- {
- // The kind of credentials this provider knows how to retrieve.
- const char * cred_kind;
- error_t (*first_credentials)(void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool);
- error_t (*next_credentials)(void ** credentials,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool);
- error_t (*save_credentials)(bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool);
- } auth_provider_t;
- // A provider object, ready to be put into an array and given to
- // create_baton_open().
- typedef struct auth_provider_object_t
- {
- const auth_provider_t * vtable;
- void * provider_baton;
- } auth_provider_object_t;
- typedef error_t (*auth_plaintext_prompt_func_t)(
- bool * may_save_plaintext,
- const char * realmstring,
- void * baton,
- apr_pool_t * pool);
- typedef error_t (*auth_password_get_t)(
- bool * done,
- const char ** password,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool);
- typedef struct auth_cred_simple_t
- {
- // Username
- const char * username;
- // Password
- const char * password;
- bool may_save;
- } auth_cred_simple_t;
- typedef struct auth_cred_username_t
- {
- // Username
- const char * username;
- bool may_save;
- } auth_cred_username_t;
- typedef error_t (*auth_password_set_t)(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * password,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool);
- // AUTH_CRED_SSL_CLIENT_CERT credentials.
- typedef struct auth_cred_ssl_client_cert_t
- {
- // Absolute path to the certificate file
- const char * cert_file;
- bool may_save;
- } auth_cred_ssl_client_cert_t;
- typedef error_t (*auth_ssl_client_cert_prompt_func_t)(
- auth_cred_ssl_client_cert_t ** cred,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool);
- typedef error_t (*auth_plaintext_passphrase_prompt_func_t)(
- bool * may_save_plaintext,
- const char * realmstring,
- void * baton,
- apr_pool_t * pool);
- // AUTH_CRED_SSL_CLIENT_CERT_PW credentials.
- typedef struct auth_cred_ssl_client_cert_pw_t
- {
- // Certificate password
- const char * password;
- bool may_save;
- } auth_cred_ssl_client_cert_pw_t;
- // AUTH_CRED_SSL_SERVER_TRUST credentials.
- typedef struct auth_cred_ssl_server_trust_t
- {
- bool may_save;
- // Bit mask of the accepted failures
- apr_uint32_t accepted_failures;
- } auth_cred_ssl_server_trust_t;
- // SSL server certificate information used by
- // AUTH_CRED_SSL_SERVER_TRUST providers.
- typedef struct auth_ssl_server_cert_info_t
- {
- // Primary CN
- const char * hostname;
- // ASCII fingerprint
- const char * fingerprint;
- // ASCII date from which the certificate is valid
- const char * valid_from;
- // ASCII date until which the certificate is valid
- const char * valid_until;
- // DN of the certificate issuer
- const char * issuer_dname;
- // Base-64 encoded DER certificate representation
- const char * ascii_cert;
- } auth_ssl_server_cert_info_t;
- typedef error_t (*auth_ssl_client_cert_pw_prompt_func_t)(
- auth_cred_ssl_client_cert_pw_t ** cred,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool);
- typedef error_t (*auth_ssl_server_trust_prompt_func_t)(
- auth_cred_ssl_server_trust_t ** cred,
- void * baton,
- const char * realm,
- apr_uint32_t failures,
- const auth_ssl_server_cert_info_t * cert_info,
- bool may_save,
- apr_pool_t * pool);
- typedef error_t (*auth_simple_prompt_func_t)(
- auth_cred_simple_t ** cred,
- void * baton,
- const char * realm,
- const char * username,
- bool may_save,
- apr_pool_t * pool);
- typedef error_t (*auth_username_prompt_func_t)(
- auth_cred_username_t ** cred,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool);
- //---------------------------------------------------------------------------
- // from config_auth.c
- #define CONST_FS_KEY "fs"
- #define CONST_FINGERPRINT_KEY "fingerprint"
- // The keys that will be stored on disk. These serve the same role as
- // similar constants in other providers.
- #define AUTHN_ASCII_CERT_KEY "ascii_cert"
- #define AUTHN_FAILURES_KEY "failures"
- static const char CertificateStorageKey[] = "HttpsCertificates";
- static error_t
- config_read_auth_data(
- apr_hash_t ** hash,
- const char * cred_kind,
- const char * realmstring,
- TWebDAVFileSystem * fs,
- apr_pool_t * pool)
- {
- const char * subkey = CertificateStorageKey;
- THierarchicalStorage * Storage = NULL;
- WEBDAV_ERR(fs->CreateStorage(Storage));
- assert(Storage);
- std::unique_ptr<THierarchicalStorage> StoragePtr;
- StoragePtr.reset(Storage);
- Storage->AccessMode = smRead;
- if (!Storage->OpenSubKey(UnicodeString(subkey), false))
- return WEBDAV_ERR_BAD_PARAM;
- *hash = apr_hash_make(pool);
- TStrings * Keys = new TStringList();
- try
- {
- Storage->GetValueNames(Keys);
- for (int Index = 0; Index < Keys->Count; ++Index)
- {
- UnicodeString Key = Keys->Strings[Index];
- UnicodeString Value = Storage->ReadStringRaw(Key, L"");
- apr_hash_set(*hash, AUTHN_ASCII_CERT_KEY, APR_HASH_KEY_STRING,
- string_create(AnsiString(Key).c_str(), pool));
- apr_hash_set(*hash, AUTHN_FAILURES_KEY, APR_HASH_KEY_STRING,
- string_createf(pool, "%lu", (unsigned long)
- StrToIntDef(Value, 0)));
- }
- }
- __finally
- {
- delete Keys;
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- config_write_auth_data(
- apr_hash_t * hash,
- const char * cred_kind,
- const char * realmstring,
- TWebDAVFileSystem * fs,
- apr_pool_t * pool)
- {
- const char * subkey = CertificateStorageKey;
- assert(fs);
- THierarchicalStorage * Storage = NULL;
- WEBDAV_ERR(fs->CreateStorage(Storage));
- assert(Storage);
- std::unique_ptr<THierarchicalStorage> StoragePtr;
- StoragePtr.reset(Storage);
- Storage->AccessMode = smReadWrite;
- if (!Storage->OpenSubKey(UnicodeString(subkey), true))
- return WEBDAV_ERR_BAD_PARAM;
- string_t * trusted_cert = static_cast<string_t *>(apr_hash_get(hash, AUTHN_ASCII_CERT_KEY,
- APR_HASH_KEY_STRING));
- string_t * failstr = static_cast<string_t *>(apr_hash_get(hash, AUTHN_FAILURES_KEY,
- APR_HASH_KEY_STRING));
- if (trusted_cert && failstr)
- Storage->WriteString(UnicodeString(trusted_cert->data), UnicodeString(failstr->data));
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from simple_providers.c
- // The keys that will be stored on disk. These serve the same role as
- // similar constants in other providers.
- #define AUTHN_USERNAME_KEY "username"
- #define AUTHN_PASSWORD_KEY "password"
- #define AUTHN_PASSTYPE_KEY "passtype"
- // Baton type for the simple provider.
- typedef struct simple_provider_baton_t
- {
- auth_plaintext_prompt_func_t plaintext_prompt_func;
- void * prompt_baton;
- // We cache the user's answer to the plaintext prompt, keyed
- // by realm, in case we'll be called multiple times for the
- // same realm.
- apr_hash_t * plaintext_answers;
- } simple_provider_baton_t;
- // Implementation of auth_password_get_t that retrieves
- // the plaintext password from CREDS.
- static error_t
- auth_simple_password_get(
- bool * done,
- const char ** password,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- *done = FALSE;
- string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING));
- if (str && username && strcmp(str->data, username) == 0)
- {
- str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_PASSWORD_KEY, APR_HASH_KEY_STRING));
- if (str && str->data)
- {
- *password = str->data;
- *done = TRUE;
- }
- }
- return WEBDAV_NO_ERROR;
- }
- // Implementation of auth_password_set_t that stores
- // the plaintext password in CREDS.
- static error_t
- auth_simple_password_set(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * password,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- apr_hash_set(creds, AUTHN_PASSWORD_KEY, APR_HASH_KEY_STRING,
- string_create(password, pool));
- *done = TRUE;
- return WEBDAV_NO_ERROR;
- }
- // Set **USERNAME to the username retrieved from CREDS; ignore
- // other parameters. *USERNAME will have the same lifetime as CREDS.
- static bool
- simple_username_get(
- const char ** username,
- apr_hash_t * creds,
- const char * realmstring,
- bool non_interactive)
- {
- string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING));
- if (str && str->data)
- {
- *username = str->data;
- return TRUE;
- }
- return FALSE;
- }
- // Common implementation for simple_first_creds. Uses PARAMETERS, REALMSTRING
- // and the simple auth provider's username and password cache to fill a set of
- // CREDENTIALS. PASSWORD_GET is used to obtain the password value.
- // PASSTYPE identifies the type of the cached password. CREDENTIALS are
- // allocated from POOL.
- static error_t
- auth_simple_first_creds_helper(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- auth_password_get_t password_get,
- const char * passtype,
- apr_pool_t * pool)
- {
- const char * username = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- APR_HASH_KEY_STRING));
- const char * password = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
- APR_HASH_KEY_STRING));
- bool non_interactive = apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
- APR_HASH_KEY_STRING) != NULL;
- const char * default_username = NULL; // Default username from cache.
- const char * default_password = NULL; // Default password from cache.
- // This checks if we should save the CREDS, if saving the credentials is
- // allowed by the run-time configuration.
- bool need_to_save = FALSE;
- apr_hash_t * creds_hash = NULL;
- error_t err = 0;
- // Try to load credentials from a file on disk, based on the
- // realmstring. Don't throw an error, though: if something went
- // wrong reading the file, no big deal. What really matters is that
- // we failed to get the creds, so allow the auth system to try the
- // next provider.
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- err = config_read_auth_data(&creds_hash, AUTH_CRED_SIMPLE,
- realmstring, fs, pool);
- if (err)
- {
- error_clear(&err);
- err = NULL;
- }
- else if (creds_hash)
- {
- // We have something in the auth cache for this realm.
- bool have_passtype = FALSE;
- // The password type in the auth data must match the
- // mangler's type, otherwise the password must be
- // interpreted by another provider.
- string_t * str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_PASSTYPE_KEY, APR_HASH_KEY_STRING));
- if (str && str->data)
- if (passtype && (0 == strcmp(str->data, passtype)))
- have_passtype = TRUE;
- // See if we need to save this username if it is not present in
- // auth cache.
- if (username)
- {
- if (!simple_username_get(&default_username, creds_hash, realmstring,
- non_interactive))
- {
- need_to_save = TRUE;
- }
- else
- {
- if (0 == strcmp(default_username, username))
- need_to_save = FALSE;
- else
- need_to_save = TRUE;
- }
- }
- // See if we need to save this password if it is not present in
- // auth cache.
- if (password)
- {
- if (have_passtype)
- {
- bool done;
- WEBDAV_ERR(password_get(&done, &default_password, creds_hash, realmstring,
- username, parameters, non_interactive, pool));
- if (!done)
- {
- need_to_save = TRUE;
- }
- else
- {
- if (0 == strcmp(default_password, password))
- need_to_save = FALSE;
- else
- need_to_save = TRUE;
- }
- }
- }
- // If we don't have a username and a password yet, we try the
- // auth cache
- if (!(username && password))
- {
- if (!username)
- if (!simple_username_get(&username, creds_hash, realmstring,
- non_interactive))
- username = NULL;
- if (username && !password)
- {
- if (!have_passtype)
- password = NULL;
- else
- {
- bool done;
- WEBDAV_ERR(password_get(&done, &password, creds_hash, realmstring,
- username, parameters, non_interactive,
- pool));
- if (!done)
- password = NULL;
- // If the auth data didn't contain a password type,
- // force a write to upgrade the format of the auth
- // data file.
- if (password && !have_passtype)
- need_to_save = TRUE;
- }
- }
- }
- }
- else
- {
- // Nothing was present in the auth cache, so indicate that these
- // credentials should be saved.
- need_to_save = TRUE;
- }
- // Ask the OS for the username if we have a password but no username.
- if (password && !username)
- username = user_get_name(pool);
- if (username && password)
- {
- auth_cred_simple_t * creds = static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*creds)));
- creds->username = username;
- creds->password = password;
- creds->may_save = need_to_save;
- *credentials = creds;
- }
- else
- *credentials = NULL;
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- // Common implementation for simple_save_creds. Uses PARAMETERS and
- // REALMSTRING to save a set of CREDENTIALS to the simple auth provider's
- // username and password cache. PASSWORD_SET is used to store the password.
- // PASSTYPE identifies the type of the cached password. Allocates from POOL.
- static error_t
- auth_simple_save_creds_helper(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- auth_password_set_t password_set,
- const char * passtype,
- apr_pool_t * pool)
- {
- auth_cred_simple_t * creds = static_cast<auth_cred_simple_t *>(credentials);
- apr_hash_t * creds_hash = NULL;
- error_t err = 0;
- bool dont_store_passwords =
- apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS,
- APR_HASH_KEY_STRING) != NULL;
- const char * store_plaintext_passwords = static_cast<const char *>(
- apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
- APR_HASH_KEY_STRING));
- bool non_interactive = apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
- APR_HASH_KEY_STRING) != NULL;
- simple_provider_baton_t * b = (simple_provider_baton_t *)provider_baton;
- bool no_auth_cache = (!creds->may_save) ||
- (apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING) != NULL);
- // Make sure we've been passed a passtype.
- WEBDAV_ERR_ASSERT(passtype != NULL);
- *saved = FALSE;
- if (no_auth_cache)
- return WEBDAV_NO_ERROR;
- // Put the username into the credentials hash.
- creds_hash = apr_hash_make(pool);
- apr_hash_set(creds_hash, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING,
- string_create(creds->username, pool));
- // Don't store passwords in any form if the user has told
- // us not to do so.
- if (!dont_store_passwords)
- {
- bool may_save_password = FALSE;
- // If the password is going to be stored encrypted, go right
- // ahead and store it to disk. Else determine whether saving
- // in plaintext is OK.
- if (passtype &&
- (strcmp(passtype, WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE) == 0))
- {
- may_save_password = TRUE;
- }
- else
- {
- if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
- WEBDAV_CONFIG_ASK) == 0)
- {
- if (non_interactive)
- // In non-interactive mode, the default behaviour is
- // to not store the password, because it is usually
- // passed on the command line.
- may_save_password = FALSE;
- else if (b && b->plaintext_prompt_func)
- {
- // We're interactive, and the client provided a
- // prompt callback. So we can ask the user.
- // Check for a cached answer before prompting.
- bool * cached_answer;
- cached_answer = static_cast<bool *>(apr_hash_get(b->plaintext_answers,
- realmstring,
- APR_HASH_KEY_STRING));
- if (cached_answer != NULL)
- may_save_password = *cached_answer;
- else
- {
- apr_pool_t * cached_answer_pool;
- // Nothing cached for this realm, prompt the user.
- WEBDAV_ERR((*b->plaintext_prompt_func)(&may_save_password,
- realmstring,
- b->prompt_baton,
- pool));
- cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
- cached_answer = static_cast<bool *>(apr_pcalloc(cached_answer_pool,
- sizeof(bool)));
- *cached_answer = may_save_password;
- apr_hash_set(b->plaintext_answers, realmstring,
- APR_HASH_KEY_STRING, cached_answer);
- }
- }
- else
- {
- may_save_password = TRUE;
- }
- }
- else if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
- WEBDAV_CONFIG_FALSE) == 0)
- {
- may_save_password = FALSE;
- }
- else if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
- WEBDAV_CONFIG_TRUE) == 0)
- {
- may_save_password = TRUE;
- }
- else
- {
- /*return error_createf
- (WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Config error: invalid value '%s' for option '%s'",
- store_plaintext_passwords,
- WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS);*/
- may_save_password = FALSE;
- }
- }
- if (may_save_password)
- {
- WEBDAV_ERR(password_set(saved, creds_hash, realmstring,
- creds->username, creds->password,
- parameters, non_interactive, pool));
- if (*saved && passtype)
- // Store the password type with the auth data, so that we
- // know which provider owns the password.
- apr_hash_set(creds_hash, AUTHN_PASSTYPE_KEY, APR_HASH_KEY_STRING,
- string_create(passtype, pool));
- }
- }
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- // Save credentials to disk.
- err = config_write_auth_data(creds_hash, AUTH_CRED_SIMPLE,
- realmstring, fs, pool);
- error_clear(&err);
- return WEBDAV_NO_ERROR;
- }
- // Get cached (unencrypted) credentials from the simple provider's cache.
- static error_t
- simple_first_creds(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_simple_first_creds_helper(credentials,
- iter_baton,
- provider_baton,
- parameters,
- realmstring,
- auth_simple_password_get,
- WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
- pool);
- }
- // Save (unencrypted) credentials to the simple provider's cache.
- static error_t
- simple_save_creds(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_simple_save_creds_helper(saved, credentials,
- provider_baton,
- parameters,
- realmstring,
- auth_simple_password_set,
- WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
- pool);
- }
- static const auth_provider_t simple_provider =
- {
- AUTH_CRED_SIMPLE,
- simple_first_creds,
- NULL,
- simple_save_creds
- };
- // Public API
- static void
- auth_get_simple_provider2(
- auth_provider_object_t ** provider,
- auth_plaintext_prompt_func_t plaintext_prompt_func,
- void * prompt_baton,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po = static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- simple_provider_baton_t * pb = static_cast<simple_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->plaintext_prompt_func = plaintext_prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->plaintext_answers = apr_hash_make(pool);
- po->vtable = &simple_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- // Baton type for username/password prompting.
- typedef struct simple_prompt_provider_baton_t
- {
- auth_simple_prompt_func_t prompt_func;
- void * prompt_baton;
- // how many times to re-prompt after the first one fails
- int retry_limit;
- } simple_prompt_provider_baton_t;
- // Iteration baton type for username/password prompting.
- typedef struct simple_prompt_iter_baton_t
- {
- // how many times we've reprompted
- int retries;
- } simple_prompt_iter_baton_t;
- // Helper Functions
- static error_t
- prompt_for_simple_creds(
- auth_cred_simple_t ** cred_p,
- simple_prompt_provider_baton_t * pb,
- apr_hash_t * parameters,
- const char * realmstring,
- bool first_time,
- bool may_save,
- apr_pool_t * pool)
- {
- const char * default_username = NULL;
- const char * default_password = NULL;
- *cred_p = NULL;
- // If we're allowed to check for default usernames and passwords, do so.
- if (first_time)
- {
- default_username = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- APR_HASH_KEY_STRING));
- // No default username? Try the auth cache.
- if (!default_username)
- {
- apr_hash_t * creds_hash = NULL;
- string_t * str;
- error_t err;
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- err = config_read_auth_data(&creds_hash, AUTH_CRED_SIMPLE,
- realmstring, fs, pool);
- error_clear(&err);
- if (!err && creds_hash)
- {
- str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_USERNAME_KEY,
- APR_HASH_KEY_STRING));
- if (str && str->data)
- default_username = str->data;
- }
- }
- // Still no default username? Try the 'servers' file.
- if (!default_username)
- {
- default_username = NULL;
- }
- // Still no default username? Try the UID.
- if (!default_username)
- default_username = user_get_name(pool);
- default_password = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
- APR_HASH_KEY_STRING));
- }
- // If we have defaults, just build the cred here and return it.
- // I do wonder why this is here instead of in a separate
- // 'defaults' provider that would run before the prompt
- // provider... Hmmm.
- if (default_username && default_password)
- {
- *cred_p = static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->username = apr_pstrdup(pool, default_username);
- (*cred_p)->password = apr_pstrdup(pool, default_password);
- (*cred_p)->may_save = TRUE;
- }
- else
- {
- WEBDAV_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
- default_username, may_save, pool));
- }
- return WEBDAV_NO_ERROR;
- }
- // Our first attempt will use any default username/password passed
- // in, and prompt for the remaining stuff.
- static error_t
- simple_prompt_first_creds(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- simple_prompt_provider_baton_t * pb =
- static_cast<simple_prompt_provider_baton_t *>(provider_baton);
- simple_prompt_iter_baton_t * ibaton =
- static_cast<simple_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ibaton)));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(prompt_for_simple_creds((auth_cred_simple_t **) credentials_p,
- pb, parameters, realmstring, TRUE,
- !no_auth_cache, pool));
- ibaton->retries = 0;
- *iter_baton = ibaton;
- return WEBDAV_NO_ERROR;
- }
- // Subsequent attempts to fetch will ignore the default values, and
- // simply re-prompt for both, up to a maximum of ib->pb->retry_limit.
- static error_t
- simple_prompt_next_creds(
- void ** credentials_p,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- simple_prompt_iter_baton_t * ib =
- static_cast<simple_prompt_iter_baton_t *>(iter_baton);
- simple_prompt_provider_baton_t * pb =
- static_cast<simple_prompt_provider_baton_t *>(provider_baton);
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
- {
- // give up, go on to next provider.
- *credentials_p = NULL;
- return WEBDAV_NO_ERROR;
- }
- ib->retries++;
- return prompt_for_simple_creds((auth_cred_simple_t **) credentials_p,
- pb, parameters, realmstring, FALSE,
- !no_auth_cache, pool);
- }
- static const auth_provider_t simple_prompt_provider =
- {
- AUTH_CRED_SIMPLE,
- simple_prompt_first_creds,
- simple_prompt_next_creds,
- NULL,
- };
- // Public API
- static void
- auth_get_simple_prompt_provider(
- auth_provider_object_t ** provider,
- auth_simple_prompt_func_t prompt_func,
- void * prompt_baton,
- int retry_limit,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- simple_prompt_provider_baton_t * pb =
- static_cast<simple_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->retry_limit = retry_limit;
- po->vtable = &simple_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //---------------------------------------------------------------------------
- // from ssl_client_cert_pw_providers.c
- // The keys that will be stored on disk. These serve the same role as
- // similar constants in other providers.
- // AUTHN_PASSTYPE_KEY just records the passphrase type next to the
- // passphrase, so that anyone who is manually editing their authn
- // files can know which provider owns the password.
- #define AUTHN_PASSPHRASE_KEY "passphrase"
- #define AUTHN_PASSTYPE_KEY "passtype"
- // Baton type for the ssl client cert passphrase provider.
- typedef struct ssl_client_cert_pw_file_provider_baton_t
- {
- auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func;
- void * prompt_baton;
- // We cache the user's answer to the plaintext prompt, keyed
- // by realm, in case we'll be called multiple times for the
- // same realm. So: keys are 'const char *' realm strings, and
- // values are 'bool *'.
- apr_hash_t * plaintext_answers;
- } ssl_client_cert_pw_file_provider_baton_t;
- // This implements the auth_password_get_t interface.
- // Set **PASSPHRASE to the plaintext passphrase retrieved from CREDS;
- // ignore other parameters.
- static error_t
- auth_ssl_client_cert_pw_get(
- bool * done,
- const char ** passphrase,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_PASSPHRASE_KEY, APR_HASH_KEY_STRING));
- if (str && str->data)
- {
- *passphrase = str->data;
- *done = TRUE;
- return WEBDAV_NO_ERROR;
- }
- *done = FALSE;
- return WEBDAV_NO_ERROR;
- }
- // This implements the auth_password_set_t interface.
- // Store PASSPHRASE in CREDS; ignore other parameters.
- static error_t
- auth_ssl_client_cert_pw_set(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * passphrase,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- apr_hash_set(creds, AUTHN_PASSPHRASE_KEY, APR_HASH_KEY_STRING,
- string_create(passphrase, pool));
- *done = TRUE;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_ssl_client_cert_pw_file_first_creds_helper(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- auth_password_get_t passphrase_get,
- const char * passtype,
- apr_pool_t * pool)
- {
- bool non_interactive = apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
- APR_HASH_KEY_STRING) != NULL;
- const char * password = NULL;
- if (!password)
- {
- error_t err;
- apr_hash_t * creds_hash = NULL;
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- // Try to load passphrase from the auth/ cache.
- err = config_read_auth_data(&creds_hash,
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- realmstring, fs, pool);
- error_clear(&err);
- if (!err && creds_hash)
- {
- bool done;
- WEBDAV_ERR(passphrase_get(&done, &password, creds_hash, realmstring,
- NULL, parameters, non_interactive, pool));
- if (!done)
- password = NULL;
- }
- }
- if (password)
- {
- auth_cred_ssl_client_cert_pw_t * cred =
- static_cast<auth_cred_ssl_client_cert_pw_t *>(apr_pcalloc(pool, sizeof(*cred)));
- cred->password = password;
- cred->may_save = FALSE;
- *credentials_p = cred;
- }
- else *credentials_p = NULL;
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_ssl_client_cert_pw_file_save_creds_helper(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- auth_password_set_t passphrase_set,
- const char * passtype,
- apr_pool_t * pool)
- {
- auth_cred_ssl_client_cert_pw_t * creds =
- static_cast<auth_cred_ssl_client_cert_pw_t *>(credentials);
- apr_hash_t * creds_hash = NULL;
- error_t err = 0;
- bool dont_store_passphrase =
- apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
- APR_HASH_KEY_STRING) != NULL;
- const char * store_ssl_client_cert_pp_plaintext =
- static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
- APR_HASH_KEY_STRING));
- bool non_interactive = apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
- APR_HASH_KEY_STRING) != NULL;
- ssl_client_cert_pw_file_provider_baton_t * b =
- (ssl_client_cert_pw_file_provider_baton_t *)provider_baton;
- bool no_auth_cache = (!creds->may_save) ||
- (apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING) != NULL);
- *saved = FALSE;
- if (no_auth_cache)
- return WEBDAV_NO_ERROR;
- creds_hash = apr_hash_make(pool);
- // Don't store passphrase in any form if the user has told
- // us not to do so.
- if (!dont_store_passphrase)
- {
- bool may_save_passphrase = FALSE;
- // If the passphrase is going to be stored encrypted, go right
- // ahead and store it to disk. Else determine whether saving
- // in plaintext is OK.
- if (strcmp(passtype, WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE) == 0)
- {
- may_save_passphrase = TRUE;
- }
- else
- {
- if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
- WEBDAV_CONFIG_ASK) == 0)
- {
- if (non_interactive)
- {
- // In non-interactive mode, the default behaviour is
- // to not store the passphrase
- may_save_passphrase = FALSE;
- }
- else if (b->plaintext_passphrase_prompt_func)
- {
- bool * cached_answer =
- static_cast<bool *>(apr_hash_get(b->plaintext_answers, realmstring,
- APR_HASH_KEY_STRING));
- if (cached_answer != NULL)
- {
- may_save_passphrase = *cached_answer;
- }
- else
- {
- apr_pool_t * cached_answer_pool;
- // Nothing cached for this realm, prompt the user.
- WEBDAV_ERR((*b->plaintext_passphrase_prompt_func)(
- &may_save_passphrase,
- realmstring,
- b->prompt_baton,
- pool));
- cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
- cached_answer = static_cast<bool *>(apr_pcalloc(cached_answer_pool,
- sizeof(*cached_answer)));
- *cached_answer = may_save_passphrase;
- apr_hash_set(b->plaintext_answers, realmstring,
- APR_HASH_KEY_STRING, cached_answer);
- }
- }
- else
- {
- may_save_passphrase = FALSE;
- }
- }
- else if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
- WEBDAV_CONFIG_FALSE) == 0)
- {
- may_save_passphrase = FALSE;
- }
- else if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
- WEBDAV_CONFIG_TRUE) == 0)
- {
- may_save_passphrase = TRUE;
- }
- else
- {
- return error_createf(WEBDAV_ERR_DAV_INVALID_CONFIG_VALUE, NULL,
- "Config error: invalid value '%s' for option '%s'",
- store_ssl_client_cert_pp_plaintext,
- WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT);
- }
- }
- if (may_save_passphrase)
- {
- WEBDAV_ERR(passphrase_set(saved, creds_hash, realmstring,
- NULL, creds->password, parameters,
- non_interactive, pool));
- if (*saved && passtype)
- {
- apr_hash_set(creds_hash, AUTHN_PASSTYPE_KEY,
- APR_HASH_KEY_STRING,
- string_create(passtype, pool));
- }
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- // Save credentials to disk.
- err = config_write_auth_data(creds_hash,
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- realmstring, fs, pool);
- error_clear(&err);
- *saved = !err;
- }
- }
- return WEBDAV_NO_ERROR;
- }
- // This implements the auth_provider_t.first_credentials API.
- // It gets cached (unencrypted) credentials from the ssl client cert
- // password provider's cache.
- static error_t
- ssl_client_cert_pw_file_first_credentials(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_ssl_client_cert_pw_file_first_creds_helper(
- credentials_p,
- iter_baton,
- provider_baton,
- parameters,
- realmstring,
- auth_ssl_client_cert_pw_get,
- WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
- pool);
- }
- // This implements the auth_provider_t.save_credentials API.
- // It saves the credentials unencrypted.
- static error_t
- ssl_client_cert_pw_file_save_credentials(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_ssl_client_cert_pw_file_save_creds_helper(
- saved, credentials,
- provider_baton,
- parameters,
- realmstring,
- auth_ssl_client_cert_pw_set,
- WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
- pool);
- }
- static const auth_provider_t ssl_client_cert_pw_file_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- ssl_client_cert_pw_file_first_credentials,
- NULL,
- ssl_client_cert_pw_file_save_credentials
- };
- // Public API to SSL file providers.
- static void
- auth_get_ssl_client_cert_pw_file_provider2(
- auth_provider_object_t ** provider,
- auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func,
- void * prompt_baton,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- ssl_client_cert_pw_file_provider_baton_t * pb =
- static_cast<ssl_client_cert_pw_file_provider_baton_t *>(apr_pcalloc(pool,
- sizeof(*pb)));
- pb->plaintext_passphrase_prompt_func = plaintext_passphrase_prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->plaintext_answers = apr_hash_make(pool);
- po->vtable = &ssl_client_cert_pw_file_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Prompt provider
- /*-----------------------------------------------------------------------*/
- // Baton type for client passphrase prompting.
- // There is no iteration baton type.
- typedef struct ssl_client_cert_pw_prompt_provider_baton_t
- {
- auth_ssl_client_cert_pw_prompt_func_t prompt_func;
- void * prompt_baton;
- // how many times to re-prompt after the first one fails
- int retry_limit;
- } ssl_client_cert_pw_prompt_provider_baton_t;
- // Iteration baton.
- typedef struct ssl_client_cert_pw_prompt_iter_baton_t
- {
- // The original provider baton
- ssl_client_cert_pw_prompt_provider_baton_t * pb;
- // The original realmstring
- const char * realmstring;
- // how many times we've reprompted
- int retries;
- } ssl_client_cert_pw_prompt_iter_baton_t;
- static error_t
- ssl_client_cert_pw_prompt_first_cred(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_client_cert_pw_prompt_provider_baton_t * pb =
- static_cast<ssl_client_cert_pw_prompt_provider_baton_t *>(provider_baton);
- ssl_client_cert_pw_prompt_iter_baton_t * ib =
- static_cast<ssl_client_cert_pw_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ib)));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_client_cert_pw_t **)
- credentials_p, pb->prompt_baton, realmstring,
- !no_auth_cache, pool));
- ib->pb = pb;
- ib->realmstring = apr_pstrdup(pool, realmstring);
- ib->retries = 0;
- *iter_baton = ib;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- ssl_client_cert_pw_prompt_next_cred(
- void ** credentials_p,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_client_cert_pw_prompt_iter_baton_t * ib =
- static_cast<ssl_client_cert_pw_prompt_iter_baton_t *>(iter_baton);
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if ((ib->pb->retry_limit >= 0) && (ib->retries >= ib->pb->retry_limit))
- {
- // give up, go on to next provider.
- *credentials_p = NULL;
- return WEBDAV_NO_ERROR;
- }
- ib->retries++;
- return ib->pb->prompt_func((auth_cred_ssl_client_cert_pw_t **)
- credentials_p, ib->pb->prompt_baton,
- ib->realmstring, !no_auth_cache, pool);
- }
- static const auth_provider_t client_cert_pw_prompt_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- ssl_client_cert_pw_prompt_first_cred,
- ssl_client_cert_pw_prompt_next_cred,
- NULL
- };
- static void
- auth_get_ssl_client_cert_pw_prompt_provider(
- auth_provider_object_t ** provider,
- auth_ssl_client_cert_pw_prompt_func_t prompt_func,
- void * prompt_baton,
- int retry_limit,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- ssl_client_cert_pw_prompt_provider_baton_t * pb =
- static_cast<ssl_client_cert_pw_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->retry_limit = retry_limit;
- po->vtable = &client_cert_pw_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //------------------------------------------------------------------------------
- // from win32_crypto.c
- // The description string that's combined with unencrypted data by the
- // Windows CryptoAPI. Used during decryption to verify that the
- // encrypted data were valid.
- static const WCHAR description[] = L"auth.simple.wincrypt";
- // Implementation of auth_password_set_t that encrypts
- // the incoming password using the Windows CryptoAPI.
- static error_t
- windows_password_encrypter(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * in,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- DATA_BLOB blobin;
- DATA_BLOB blobout;
- BOOL crypted = FALSE;
- blobin.cbData = (DWORD)strlen(in);
- blobin.pbData = (BYTE *) in;
- crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
- CRYPTPROTECT_UI_FORBIDDEN, &blobout);
- if (crypted)
- {
- char * coded = static_cast<char *>(apr_pcalloc(pool, apr_base64_encode_len(blobout.cbData)));
- apr_base64_encode(coded, (const char *)blobout.pbData, blobout.cbData);
- WEBDAV_ERR(auth_simple_password_set(done, creds, realmstring, username,
- coded, parameters,
- non_interactive, pool));
- LocalFree(blobout.pbData);
- }
- return WEBDAV_NO_ERROR;
- }
- // Implementation of auth_password_get_t that decrypts
- // the incoming password using the Windows CryptoAPI and verifies its
- // validity.
- static error_t
- windows_password_decrypter(
- bool * done,
- const char ** out,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- DATA_BLOB blobin;
- DATA_BLOB blobout;
- LPWSTR descr;
- BOOL decrypted = FALSE;
- const char * in = NULL;
- WEBDAV_ERR(auth_simple_password_get(done, &in, creds, realmstring, username,
- parameters, non_interactive, pool));
- if (!*done)
- return WEBDAV_NO_ERROR;
- blobin.cbData = (DWORD)strlen(in);
- blobin.pbData = static_cast<BYTE *>(apr_pcalloc(pool, apr_base64_decode_len(in)));
- apr_base64_decode((char *)blobin.pbData, in);
- decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
- CRYPTPROTECT_UI_FORBIDDEN, &blobout);
- if (decrypted)
- {
- if (0 == lstrcmpW(descr, description))
- *out = apr_pstrndup(pool, (const char *)blobout.pbData, blobout.cbData);
- else
- decrypted = FALSE;
- LocalFree(blobout.pbData);
- LocalFree(descr);
- }
- *done = decrypted != 0;
- return WEBDAV_NO_ERROR;
- }
- // Get cached encrypted credentials from the simple provider's cache.
- static error_t
- windows_simple_first_creds(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_simple_first_creds_helper(credentials,
- iter_baton,
- provider_baton,
- parameters,
- realmstring,
- windows_password_decrypter,
- WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
- pool);
- }
- // Save encrypted credentials to the simple provider's cache.
- static error_t
- windows_simple_save_creds(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_simple_save_creds_helper(saved, credentials,
- provider_baton,
- parameters,
- realmstring,
- windows_password_encrypter,
- WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
- pool);
- }
- static const auth_provider_t windows_simple_provider =
- {
- AUTH_CRED_SIMPLE,
- windows_simple_first_creds,
- NULL,
- windows_simple_save_creds
- };
- // Public API
- static void
- auth_get_windows_simple_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &windows_simple_provider;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Windows SSL server trust provider, validates ssl certificate using
- // CryptoApi.
- /*-----------------------------------------------------------------------*/
- // Implementation of auth_password_set_t that encrypts
- // the incoming password using the Windows CryptoAPI.
- static error_t
- windows_ssl_client_cert_pw_encrypter(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * in,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- DATA_BLOB blobin;
- DATA_BLOB blobout;
- BOOL crypted;
- blobin.cbData = (DWORD)strlen(in);
- blobin.pbData = (BYTE *) in;
- crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
- CRYPTPROTECT_UI_FORBIDDEN, &blobout);
- if (crypted)
- {
- char * coded = static_cast<char *>(apr_pcalloc(pool, apr_base64_encode_len(blobout.cbData)));
- apr_base64_encode(coded, (const char *)blobout.pbData, blobout.cbData);
- WEBDAV_ERR(auth_ssl_client_cert_pw_set(done, creds, realmstring, username,
- coded, parameters,
- non_interactive, pool));
- LocalFree(blobout.pbData);
- }
- return WEBDAV_NO_ERROR;
- }
- // Implementation of auth_password_get_t that decrypts
- // the incoming password using the Windows CryptoAPI and verifies its
- // validity.
- static error_t
- windows_ssl_client_cert_pw_decrypter(
- bool * done,
- const char ** out,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- DATA_BLOB blobin;
- DATA_BLOB blobout;
- LPWSTR descr;
- BOOL decrypted;
- const char * in = NULL;
- WEBDAV_ERR(auth_ssl_client_cert_pw_get(done, &in, creds, realmstring, username,
- parameters, non_interactive, pool));
- if (!*done)
- return WEBDAV_NO_ERROR;
- blobin.cbData = (DWORD)strlen(in);
- blobin.pbData = static_cast<BYTE *>(apr_pcalloc(pool, apr_base64_decode_len(in)));
- apr_base64_decode((char *)blobin.pbData, in);
- decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
- CRYPTPROTECT_UI_FORBIDDEN, &blobout);
- if (decrypted)
- {
- if (0 == lstrcmpW(descr, description))
- *out = apr_pstrndup(pool, (const char *)blobout.pbData, blobout.cbData);
- else
- decrypted = FALSE;
- LocalFree(blobout.pbData);
- LocalFree(descr);
- }
- *done = decrypted != 0;
- return WEBDAV_NO_ERROR;
- }
- // Get cached encrypted credentials from the simple provider's cache.
- static error_t
- windows_ssl_client_cert_pw_first_creds(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_ssl_client_cert_pw_file_first_creds_helper(
- credentials,
- iter_baton,
- provider_baton,
- parameters,
- realmstring,
- windows_ssl_client_cert_pw_decrypter,
- WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
- pool);
- }
- // Save encrypted credentials to the simple provider's cache.
- static error_t
- windows_ssl_client_cert_pw_save_creds(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_ssl_client_cert_pw_file_save_creds_helper(
- saved,
- credentials,
- provider_baton,
- parameters,
- realmstring,
- windows_ssl_client_cert_pw_encrypter,
- WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
- pool);
- }
- static const auth_provider_t windows_ssl_client_cert_pw_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- windows_ssl_client_cert_pw_first_creds,
- NULL,
- windows_ssl_client_cert_pw_save_creds
- };
- // Public API
- static void
- auth_get_windows_ssl_client_cert_pw_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &windows_ssl_client_cert_pw_provider;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Windows SSL server trust provider, validates ssl certificate using
- // CryptoApi.
- /*-----------------------------------------------------------------------*/
- // Helper to create CryptoAPI CERT_CONTEXT from base64 encoded BASE64_CERT.
- // Returns NULL on error.
- static PCCERT_CONTEXT
- certcontext_from_base64(
- const char * base64_cert,
- apr_pool_t * pool)
- {
- PCCERT_CONTEXT cert_context = NULL;
- int cert_len = 0;
- BYTE * binary_cert = NULL;
- // Use apr-util as CryptStringToBinaryA is available only on XP+.
- binary_cert = static_cast<BYTE *>(apr_pcalloc(pool,
- apr_base64_decode_len(base64_cert)));
- cert_len = apr_base64_decode((char *)binary_cert, base64_cert);
- // Parse the certificate into a context.
- cert_context = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- binary_cert, cert_len);
- return cert_context;
- }
- // Helper for windows_ssl_server_trust_first_credentials for validating
- // certificate using CryptoApi. Sets *OK_P to TRUE if base64 encoded ASCII_CERT
- // certificate considered as valid.
- static error_t
- windows_validate_certificate(
- bool * ok_p,
- const char * ascii_cert,
- apr_pool_t * pool)
- {
- PCCERT_CONTEXT cert_context = NULL;
- CERT_CHAIN_PARA chain_para;
- PCCERT_CHAIN_CONTEXT chain_context = NULL;
- *ok_p = FALSE;
- // Parse the certificate into a context.
- cert_context = certcontext_from_base64(ascii_cert, pool);
- if (cert_context)
- {
- // Retrieve the certificate chain of the certificate
- // (a certificate without a valid root does not have a chain).
- memset(&chain_para, 0, sizeof(chain_para));
- chain_para.cbSize = sizeof(chain_para);
- HCERTCHAINENGINE chain_engine;
- CERT_CHAIN_ENGINE_CONFIG chain_config;
- chain_config.cbSize = sizeof(CERT_CHAIN_ENGINE_CONFIG);
- chain_config.hRestrictedRoot = NULL;
- chain_config.hRestrictedTrust = NULL;
- chain_config.hRestrictedOther = NULL;
- chain_config.cAdditionalStore = 0;
- chain_config.rghAdditionalStore = NULL;
- chain_config.dwFlags = CERT_CHAIN_CACHE_END_CERT;
- chain_config.dwUrlRetrievalTimeout = 0;
- chain_config.MaximumCachedCertificates =0;
- chain_config.CycleDetectionModulus = 0;
- CertCreateCertificateChainEngine(
- &chain_config,
- &chain_engine);
- if (CertGetCertificateChain(chain_engine, cert_context, NULL, NULL, &chain_para,
- CERT_CHAIN_CACHE_END_CERT |
- CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
- NULL, &chain_context))
- {
- CERT_CHAIN_POLICY_PARA policy_para;
- CERT_CHAIN_POLICY_STATUS policy_status;
- policy_para.cbSize = sizeof(policy_para);
- policy_para.dwFlags = 0;
- policy_para.pvExtraPolicyPara = NULL;
- policy_status.cbSize = sizeof(policy_status);
- if (CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
- chain_context, &policy_para,
- &policy_status))
- {
- if (policy_status.dwError == S_OK)
- {
- // Windows thinks the certificate is valid.
- *ok_p = TRUE;
- }
- }
- CertFreeCertificateChain(chain_context);
- }
- CertFreeCertificateContext(cert_context);
- CertFreeCertificateChainEngine(chain_engine);
- }
- return WEBDAV_NO_ERROR;
- }
- // Retrieve ssl server CA failure overrides (if any) from CryptoApi.
- static error_t
- windows_ssl_server_trust_first_credentials(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_FAILURES,
- APR_HASH_KEY_STRING));
- const auth_ssl_server_cert_info_t * cert_info =
- static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- APR_HASH_KEY_STRING));
- *credentials = NULL;
- *iter_baton = NULL;
- // We can accept only unknown certificate authority.
- if (*failures & WEBDAV_AUTH_SSL_UNKNOWNCA)
- {
- bool ok;
- WEBDAV_ERR(windows_validate_certificate(&ok, cert_info->ascii_cert, pool));
- // Windows thinks that certificate is ok.
- if (ok)
- {
- // Clear failure flag.
- *failures &= ~WEBDAV_AUTH_SSL_UNKNOWNCA;
- }
- }
- // If all failures are cleared now, we return the creds
- if (!*failures)
- {
- auth_cred_ssl_server_trust_t * creds =
- static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(*creds)));
- creds->may_save = FALSE; // No need to save it.
- *credentials = creds;
- }
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t windows_server_trust_provider =
- {
- AUTH_CRED_SSL_SERVER_TRUST,
- windows_ssl_server_trust_first_credentials,
- NULL,
- NULL,
- };
- // Public API
- static void
- auth_get_windows_ssl_server_trust_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &windows_server_trust_provider;
- *provider = po;
- }
- //------------------------------------------------------------------------------
- // from username_providers.c
- // Username-only Provider
- static error_t
- username_first_creds(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- const char * username = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- APR_HASH_KEY_STRING));
- bool may_save = !!username;
- error_t err = 0;
- // If we don't have a usename yet, try the auth cache
- if (!username)
- {
- apr_hash_t * creds_hash = NULL;
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- // Try to load credentials from a file on disk, based on the
- // realmstring. Don't throw an error, though: if something went
- // wrong reading the file, no big deal. What really matters is that
- // we failed to get the creds, so allow the auth system to try the
- // next provider.
- err = config_read_auth_data(&creds_hash, WEBDAV_AUTH_CRED_USERNAME,
- realmstring, fs,
- pool);
- error_clear(&err);
- if (!err && creds_hash)
- {
- string_t * str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_USERNAME_KEY,
- APR_HASH_KEY_STRING));
- if (str && str->data)
- username = str->data;
- }
- }
- // If that failed, ask the OS for the username
- if (!username)
- username = user_get_name(pool);
- if (username)
- {
- auth_cred_simple_t * creds =
- static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*creds)));
- creds->username = username;
- creds->may_save = may_save;
- *credentials = creds;
- }
- else
- *credentials = NULL;
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- username_save_creds(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- auth_cred_simple_t * creds =
- static_cast<auth_cred_simple_t *>(credentials);
- apr_hash_t * creds_hash = NULL;
- error_t err;
- *saved = FALSE;
- if (!creds->may_save)
- return WEBDAV_NO_ERROR;
- // Put the credentials in a hash and save it to disk
- creds_hash = apr_hash_make(pool);
- apr_hash_set(creds_hash, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING,
- string_create(creds->username, pool));
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- err = config_write_auth_data(creds_hash, WEBDAV_AUTH_CRED_USERNAME,
- realmstring,
- fs,
- pool);
- error_clear(&err);
- *saved = !err;
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t username_provider =
- {
- WEBDAV_AUTH_CRED_USERNAME,
- username_first_creds,
- NULL,
- username_save_creds
- };
- // Public API
- static void
- auth_get_username_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &username_provider;
- *provider = po;
- }
- // Baton type for username-only prompting.
- typedef struct username_prompt_provider_baton_t
- {
- auth_username_prompt_func_t prompt_func;
- void * prompt_baton;
- // how many times to re-prompt after the first one fails
- int retry_limit;
- } username_prompt_provider_baton_t;
- // Iteration baton type for username-only prompting.
- typedef struct username_prompt_iter_baton_t
- {
- // how many times we've reprompted
- int retries;
- } username_prompt_iter_baton_t;
- // Helper Functions
- static error_t
- prompt_for_username_creds(
- auth_cred_username_t ** cred_p,
- username_prompt_provider_baton_t * pb,
- apr_hash_t * parameters,
- const char * realmstring,
- bool first_time,
- bool may_save,
- apr_pool_t * pool)
- {
- const char * def_username = NULL;
- *cred_p = NULL;
- // If we're allowed to check for default usernames, do so.
- if (first_time)
- def_username = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- APR_HASH_KEY_STRING));
- // If we have defaults, just build the cred here and return it.
- // I do wonder why this is here instead of in a separate
- // 'defaults' provider that would run before the prompt
- // provider... Hmmm.
- if (def_username)
- {
- *cred_p = static_cast<auth_cred_username_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->username = apr_pstrdup(pool, def_username);
- (*cred_p)->may_save = TRUE;
- }
- else
- {
- WEBDAV_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
- may_save, pool));
- }
- return WEBDAV_NO_ERROR;
- }
- // Our first attempt will use any default username passed
- // in, and prompt for the remaining stuff.
- static error_t
- username_prompt_first_creds(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- username_prompt_provider_baton_t * pb =
- static_cast<username_prompt_provider_baton_t *>(provider_baton);
- username_prompt_iter_baton_t * ibaton =
- static_cast<username_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ibaton)));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(prompt_for_username_creds((auth_cred_username_t **) credentials_p, pb,
- parameters, realmstring, TRUE, !no_auth_cache, pool));
- ibaton->retries = 0;
- *iter_baton = ibaton;
- return WEBDAV_NO_ERROR;
- }
- // Subsequent attempts to fetch will ignore the default username
- // value, and simply re-prompt for the username, up to a maximum of
- // ib->pb->retry_limit.
- static error_t
- username_prompt_next_creds(
- void ** credentials_p,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- username_prompt_iter_baton_t * ib =
- static_cast<username_prompt_iter_baton_t *>(iter_baton);
- username_prompt_provider_baton_t * pb =
- static_cast<username_prompt_provider_baton_t *>(provider_baton);
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
- {
- // give up, go on to next provider.
- *credentials_p = NULL;
- return WEBDAV_NO_ERROR;
- }
- ib->retries++;
- return prompt_for_username_creds((auth_cred_username_t **) credentials_p, pb,
- parameters, realmstring, FALSE, !no_auth_cache, pool);
- }
- static const auth_provider_t username_prompt_provider =
- {
- WEBDAV_AUTH_CRED_USERNAME,
- username_prompt_first_creds,
- username_prompt_next_creds,
- NULL,
- };
- // Public API
- static void
- auth_get_username_prompt_provider(
- auth_provider_object_t ** provider,
- auth_username_prompt_func_t prompt_func,
- void * prompt_baton,
- int retry_limit,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- username_prompt_provider_baton_t * pb =
- static_cast<username_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->retry_limit = retry_limit;
- po->vtable = &username_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //------------------------------------------------------------------------------
- // from auth.c
- static void
- auth_baton_set_parameter(
- auth_baton_t * auth_baton,
- const char * name,
- const void * value)
- {
- apr_hash_set(auth_baton->parameters, name, APR_HASH_KEY_STRING, value);
- }
- static const void *
- auth_baton_get_parameter(
- auth_baton_t * auth_baton,
- const char * name)
- {
- return apr_hash_get(auth_baton->parameters, name, APR_HASH_KEY_STRING);
- }
- static error_t
- auth_first_credentials(
- void ** credentials,
- auth_iterstate_t ** state,
- const char * cred_kind,
- const char * realmstring,
- auth_baton_t * auth_baton,
- apr_pool_t * pool)
- {
- int i = 0;
- provider_set_t * table = NULL;
- auth_provider_object_t * provider = NULL;
- void * creds = NULL;
- void * iter_baton = NULL;
- bool got_first = FALSE;
- auth_iterstate_t * iterstate = NULL;
- const char * cache_key = NULL;
- // Get the appropriate table of providers for CRED_KIND.
- table = static_cast<provider_set_t *>(apr_hash_get(auth_baton->tables, cred_kind, APR_HASH_KEY_STRING));
- if (!table)
- return error_createf(WEBDAV_ERR_AUTHN_NO_PROVIDER, NULL,
- "No provider registered for '%s' credentials",
- cred_kind);
- // First, see if we have cached creds in the auth_baton.
- cache_key = apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
- creds = static_cast<void *>(apr_hash_get(auth_baton->creds_cache,
- cache_key, APR_HASH_KEY_STRING));
- if (creds)
- {
- got_first = false;
- }
- else
- // If not, find a provider that can give "first" credentials.
- {
- // Find a provider that can give "first" credentials.
- for (i = 0; i < table->providers->nelts; i++)
- {
- provider = APR_ARRAY_IDX(table->providers, i,
- auth_provider_object_t *);
- WEBDAV_ERR(provider->vtable->first_credentials(
- &creds, &iter_baton, provider->provider_baton,
- auth_baton->parameters, realmstring, auth_baton->pool));
- if (creds != NULL)
- {
- got_first = true;
- break;
- }
- }
- }
- if (!creds)
- *state = NULL;
- else
- {
- // Build an abstract iteration state.
- iterstate = static_cast<auth_iterstate_t *>(apr_pcalloc(pool, sizeof(*iterstate)));
- iterstate->table = table;
- iterstate->provider_idx = i;
- iterstate->got_first = got_first;
- iterstate->provider_iter_baton = iter_baton;
- iterstate->realmstring = apr_pstrdup(pool, realmstring);
- iterstate->cache_key = cache_key;
- iterstate->auth_baton = auth_baton;
- *state = iterstate;
- // Put the creds in the cache
- apr_hash_set(auth_baton->creds_cache,
- apr_pstrdup(auth_baton->pool, cache_key),
- APR_HASH_KEY_STRING,
- creds);
- }
- *credentials = creds;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_next_credentials(
- void ** credentials,
- auth_iterstate_t * state,
- apr_pool_t * pool)
- {
- auth_baton_t * auth_baton = state->auth_baton;
- auth_provider_object_t * provider = NULL;
- provider_set_t * table = state->table;
- void * creds = NULL;
- // Continue traversing the table from where we left off.
- for (/* no init */;
- state->provider_idx < table->providers->nelts;
- state->provider_idx++)
- {
- provider = APR_ARRAY_IDX(table->providers,
- state->provider_idx,
- auth_provider_object_t *);
- if (!state->got_first)
- {
- WEBDAV_ERR(provider->vtable->first_credentials(
- &creds, &(state->provider_iter_baton),
- provider->provider_baton, auth_baton->parameters,
- state->realmstring, auth_baton->pool));
- state->got_first = TRUE;
- }
- else
- {
- if (provider->vtable->next_credentials)
- WEBDAV_ERR(provider->vtable->next_credentials(
- &creds, state->provider_iter_baton,
- provider->provider_baton, auth_baton->parameters,
- state->realmstring, auth_baton->pool));
- }
- if (creds != NULL)
- {
- // Put the creds in the cache
- apr_hash_set(auth_baton->creds_cache,
- state->cache_key, APR_HASH_KEY_STRING,
- creds);
- break;
- }
- state->got_first = FALSE;
- }
- *credentials = creds;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_save_credentials(
- auth_iterstate_t * state,
- apr_pool_t * pool)
- {
- int i = 0;
- auth_provider_object_t * provider = NULL;
- bool save_succeeded = FALSE;
- const char * no_auth_cache = NULL;
- auth_baton_t * auth_baton = NULL;
- void * creds = NULL;
- if (!state || state->table->providers->nelts <= state->provider_idx)
- return WEBDAV_NO_ERROR;
- auth_baton = state->auth_baton;
- creds = apr_hash_get(state->auth_baton->creds_cache,
- state->cache_key, APR_HASH_KEY_STRING);
- if (!creds)
- return WEBDAV_NO_ERROR;
- // Do not save the creds if AUTH_PARAM_NO_AUTH_CACHE is set
- no_auth_cache = static_cast<const char *>(apr_hash_get(auth_baton->parameters,
- AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if (no_auth_cache)
- return WEBDAV_NO_ERROR;
- // First, try to save the creds using the provider that produced them.
- provider = APR_ARRAY_IDX(state->table->providers,
- state->provider_idx,
- auth_provider_object_t *);
- if (provider->vtable->save_credentials)
- WEBDAV_ERR(provider->vtable->save_credentials(&save_succeeded,
- creds,
- provider->provider_baton,
- auth_baton->parameters,
- state->realmstring,
- pool));
- if (save_succeeded)
- return WEBDAV_NO_ERROR;
- // Otherwise, loop from the top of the list, asking every provider
- // to attempt a save. todo: someday optimize so we don't
- // necessarily start from the top of the list.
- for (i = 0; i < state->table->providers->nelts; i++)
- {
- provider = APR_ARRAY_IDX(state->table->providers, i,
- auth_provider_object_t *);
- if (provider->vtable->save_credentials)
- WEBDAV_ERR(provider->vtable->save_credentials(
- &save_succeeded, creds,
- provider->provider_baton,
- auth_baton->parameters,
- state->realmstring,
- pool));
- if (save_succeeded)
- break;
- }
- // notice that at the moment, if no provider can save, there's
- // no way the caller will know.
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_get_platform_specific_provider(
- auth_provider_object_t ** provider,
- const char * provider_name,
- const char * provider_type,
- apr_pool_t * pool)
- {
- *provider = NULL;
- {
- if (strcmp(provider_name, "windows") == 0 &&
- strcmp(provider_type, "simple") == 0)
- {
- auth_get_windows_simple_provider(provider, pool);
- }
- else if (strcmp(provider_name, "windows") == 0 &&
- strcmp(provider_type, "ssl_client_cert_pw") == 0)
- {
- auth_get_windows_ssl_client_cert_pw_provider(provider, pool);
- }
- else if (strcmp(provider_name, "windows") == 0 &&
- strcmp(provider_type, "ssl_server_trust") == 0)
- {
- auth_get_windows_ssl_server_trust_provider(provider, pool);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- #define WEBDAV_MAYBE_ADD_PROVIDER(list, p) \
- { if (p) APR_ARRAY_PUSH(list, auth_provider_object_t *) = p; }
- static error_t
- auth_get_platform_specific_client_providers(
- apr_array_header_t ** providers,
- apr_pool_t * pool)
- {
- auth_provider_object_t * provider;
- const char * password_stores_config_option;
- apr_array_header_t * password_stores;
- int i;
- password_stores_config_option = "windows-cryptoapi";
- *providers = apr_array_make(pool, 12, sizeof(auth_provider_object_t *));
- password_stores = cstring_split(password_stores_config_option, " ,", TRUE, pool);
- for (i = 0; i < password_stores->nelts; i++)
- {
- const char * password_store = APR_ARRAY_IDX(password_stores, i,
- const char *);
- // Windows
- if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
- {
- WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
- "windows",
- "simple",
- pool));
- WEBDAV_MAYBE_ADD_PROVIDER(*providers, provider);
- WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
- "windows",
- "ssl_client_cert_pw",
- pool));
- WEBDAV_MAYBE_ADD_PROVIDER(*providers, provider);
- continue;
- }
- return error_createf(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Invalid config: unknown password store "
- "'%s'",
- password_store);
- }
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from dirent_uri.c
- // TRUE if s is the canonical empty path, FALSE otherwise
- #define PATH_IS_EMPTY(s) ((s)[0] == '\0')
- // Path separator for local filesystem
- #define WEBDAV_PATH_LOCAL_SEPARATOR '\\'
- // Path type definition. Used only by internal functions.
- typedef enum path_type_t
- {
- type_uri,
- type_dirent,
- type_relpath
- } path_type_t;
- // Locale insensitive tolower() for converting parts of dirents and urls
- // while canonicalizing
- static char
- canonicalize_to_lower(char c)
- {
- if (!IsUpperCaseLetter(c))
- return c;
- else
- return c - 'A' + 'a';
- }
- // Locale insensitive toupper() for converting parts of dirents and urls
- // while canonicalizing
- static char
- canonicalize_to_upper(char c)
- {
- if (!IsLowerCaseLetter(c))
- return c;
- else
- return c - 'a' + 'A';
- }
- // Return the canonicalized version of PATH, of type TYPE, allocated in POOL.
- static const char *
- canonicalize(
- path_type_t type,
- const char * path,
- apr_pool_t * pool)
- {
- char * canon = NULL, *dst = NULL;
- const char * src = NULL;
- size_t seglen = 0;
- size_t schemelen = 0;
- size_t canon_segments = 0;
- bool url = FALSE;
- char * schema_data = NULL;
- // "" is already canonical, so just return it; note that later code
- // depends on path not being zero-length.
- if (PATH_IS_EMPTY(path))
- {
- assert(type != type_uri);
- return "";
- }
- dst = canon = static_cast<char *>(apr_pcalloc(pool, strlen(path) + 1));
- // If this is supposed to be an URI, it should start with
- // "scheme://". We'll copy the scheme, host name, etc. to DST and
- // set URL = TRUE.
- src = path;
- if (type == type_uri)
- {
- assert(*src != '/');
- while (*src && (*src != '/') && (*src != ':'))
- src++;
- if ((*src == ':') && (*(src+1) == '/') && (*(src+2) == '/'))
- {
- const char * seg;
- url = TRUE;
- // Found a scheme, convert to lowercase and copy to dst.
- src = path;
- while (*src != ':')
- {
- *(dst++) = canonicalize_to_lower((*src++));
- schemelen++;
- }
- *(dst++) = ':';
- *(dst++) = '/';
- *(dst++) = '/';
- src += 3;
- schemelen += 3;
- // This might be the hostname
- seg = src;
- while (*src && (*src != '/') && (*src != '@'))
- src++;
- if (*src == '@')
- {
- // Copy the username & password.
- seglen = src - seg + 1;
- memcpy(dst, seg, seglen);
- dst += seglen;
- src++;
- }
- else
- src = seg;
- // Found a hostname, convert to lowercase and copy to dst.
- while (*src && (*src != '/') && (*src != ':'))
- *(dst++) = canonicalize_to_lower((*src++));
- if (*src == ':')
- {
- // We probably have a port number: Is it a default portnumber
- // which doesn't belong in a canonical url?
- if ((src[1] == '8') && (src[2] == '0') &&
- ((src[3] == '/') || !src[3]) &&
- !strncmp(canon, "http:", 5))
- {
- src += 3;
- }
- else if ((src[1] == '4') && (src[2] == '4') && (src[3] == '3') &&
- ((src[4] == '/') || !src[4]) &&
- !strncmp(canon, "https:", 6))
- {
- src += 4;
- }
- else if ((src[1] == '/') || !src[1])
- {
- src += 1;
- }
- while (*src && (*src != '/'))
- *(dst++) = canonicalize_to_lower((*src++));
- }
- // Copy trailing slash, or null-terminator.
- *(dst) = *(src);
- // Move src and dst forward only if we are not
- // at null-terminator yet.
- if (*src)
- {
- src++;
- dst++;
- schema_data = dst;
- }
- canon_segments = 1;
- }
- }
- // Copy to DST any separator or drive letter that must come before the
- // first regular path segment.
- if (!url && type != type_relpath)
- {
- src = path;
- // If this is an absolute path, then just copy over the initial
- // separator character.
- if (*src == '/')
- {
- *(dst++) = *(src++);
- // On Windows permit two leading separator characters which means an
- // UNC path.
- if ((type == type_dirent) && (*src == '/'))
- *(dst++) = *(src++);
- }
- // On Windows the first segment can be a drive letter, which we normalize
- // to upper case.
- else if ((type == type_dirent) &&
- IsLetter(*src) &&
- (src[1] == ':'))
- {
- *(dst++) = canonicalize_to_upper(*(src++));
- // Leave the ':' to be processed as (or as part of) a path segment
- // by the following code block, so we need not care whether it has
- // a slash after it.
- }
- }
- while (*src)
- {
- // Parse each segment, finding the closing '/' (which might look
- // like '%2F' for URIs).
- const char * next = src;
- size_t slash_len = 0;
- while (*next &&
- (next[0] != '/') &&
- (!((type == type_uri) && (next[0] == '%') && (next[1] == '2') &&
- (canonicalize_to_upper(next[2]) == 'F'))))
- {
- ++next;
- }
- // Record how long our "slash" is.
- if (next[0] == '/')
- slash_len = 1;
- else if ((type == type_uri) && (next[0] == '%'))
- slash_len = 3;
- seglen = next - src;
- if ((seglen == 0) ||
- ((seglen == 1) && (src[0] == '.')) ||
- ((type == type_uri) && (seglen == 3) && (src[0] == '%') && (src[1] == '2') &&
- (canonicalize_to_upper(src[2]) == 'E')))
- {
- // Empty or noop segment, so do nothing. (For URIs, '%2E'
- // is equivalent to '.').
- }
- // If this is the first path segment of a file:// URI and it contains a
- // windows drive letter, convert the drive letter to upper case.
- else if (url && (canon_segments == 1) && (seglen == 2) &&
- (strncmp(canon, "file:", 5) == 0) &&
- IsLowerCaseLetter(src[0]) && (src[1] == ':'))
- {
- *(dst++) = canonicalize_to_upper(src[0]);
- *(dst++) = ':';
- if (*next)
- *(dst++) = *next;
- canon_segments++;
- }
- else
- {
- // An actual segment, append it to the destination path
- memcpy(dst, src, seglen);
- dst += seglen;
- if (slash_len)
- {
- *(dst++) = '/';
- }
- canon_segments++;
- }
- // Skip over trailing slash to the next segment.
- src = next + slash_len;
- }
- *dst = '\0';
- // Skip leading double slashes when there are less than 2
- // canon segments. UNC paths *MUST* have two segments.
- if ((type == type_dirent) && (canon[0] == '/') && (canon[1] == '/'))
- {
- if (canon_segments < 2)
- return canon + 1;
- else
- {
- // Now we're sure this is a valid UNC path, convert the server name
- // (the first path segment) to lowercase as Windows treats it as case
- // insensitive.
- // Note: normally the share name is treated as case insensitive too,
- // but it seems to be possible to configure Samba to treat those as
- // case sensitive, so better leave that alone.
- for (dst = canon + 2; *dst && (*dst != '/'); dst++)
- *dst = canonicalize_to_lower(*dst);
- }
- }
- // Check the normalization of characters in a uri
- if (schema_data)
- {
- int need_extra = 0;
- src = schema_data;
- while (*src)
- {
- switch (*src)
- {
- case '/':
- break;
- case '%':
- if (!ctype_isxdigit(*(src+1)) ||
- !ctype_isxdigit(*(src+2)))
- need_extra += 2;
- else
- src += 2;
- break;
- default:
- if (!uri_char_validity[(unsigned char)*src])
- need_extra += 2;
- break;
- }
- src++;
- }
- if (need_extra > 0)
- {
- size_t pre_schema_size = (size_t)(schema_data - canon);
- dst = static_cast<char *>(apr_pcalloc(pool, (size_t)(src - canon) + need_extra + 1));
- memcpy(dst, canon, pre_schema_size);
- canon = dst;
- dst += pre_schema_size;
- }
- else
- dst = schema_data;
- src = schema_data;
- while (*src)
- {
- switch (*src)
- {
- case '/':
- *(dst++) = '/';
- break;
- case '%':
- if (!ctype_isxdigit(*(src+1)) ||
- !ctype_isxdigit(*(src+2)))
- {
- *(dst++) = '%';
- *(dst++) = '2';
- *(dst++) = '5';
- }
- else
- {
- char digitz[3];
- int val;
- digitz[0] = *(++src);
- digitz[1] = *(++src);
- digitz[2] = 0;
- val = (int)strtol(digitz, NULL, 16);
- if (uri_char_validity[(unsigned char)val])
- *(dst++) = (char)val;
- else
- {
- *(dst++) = '%';
- *(dst++) = canonicalize_to_upper(digitz[0]);
- *(dst++) = canonicalize_to_upper(digitz[1]);
- }
- }
- break;
- default:
- if (!uri_char_validity[(unsigned char)*src])
- {
- apr_snprintf(dst, 4, "%%%02X", (unsigned char)*src);
- dst += 3;
- }
- else
- *(dst++) = *src;
- break;
- }
- src++;
- }
- *dst = '\0';
- }
- return canon;
- }
- static const char *
- uri_canonicalize(
- const char * uri,
- apr_pool_t * pool)
- {
- return canonicalize(type_uri, uri, pool);
- }
- static const char *
- relpath_canonicalize(
- const char * relpath,
- apr_pool_t * pool)
- {
- return canonicalize(type_relpath, relpath, pool);
- }
- static const char *
- fspath_canonicalize(
- const char * fspath,
- apr_pool_t * pool)
- {
- if ((fspath[0] == '/') && (fspath[1] == '\0'))
- return "/";
- return apr_pstrcat(pool, "/", relpath_canonicalize(fspath, pool),
- (char *)NULL);
- }
- // Examine PATH as a potential URI, and return a substring of PATH
- // that immediately follows the (scheme):// portion of the URI, or
- // NULL if PATH doesn't appear to be a valid URI. The returned value
- // is not allocated -- it shares memory with PATH.
- static const char *
- skip_uri_scheme(
- const char * path)
- {
- size_t j = 0;
- // A scheme is terminated by a : and cannot contain any /'s.
- for (j = 0; path[j] && (path[j] != ':'); ++j)
- if (path[j] == '/')
- return NULL;
- if ((j > 0) && (path[j] == ':') && (path[j+1] == '/') && (path[j+2] == '/'))
- return path + j + 3;
- return NULL;
- }
- static bool
- path_is_url(
- const char * path)
- {
- // This function is reaaaaaaaaaaaaaally stupid right now.
- // We're just going to look for:
- // (scheme)://(optional_stuff)
- // Where (scheme) has no ':' or '/' characters.
- // Someday it might be nice to have an actual URI parser here.
- return skip_uri_scheme(path) != NULL;
- }
- static const char *
- urlpath_canonicalize(
- const char * uri,
- apr_pool_t * pool)
- {
- if (path_is_url(uri))
- {
- uri = uri_canonicalize(uri, pool);
- }
- else
- {
- uri = fspath_canonicalize(uri, pool);
- // Do a little dance to normalize hex encoding.
- uri = path_uri_decode(uri, pool);
- uri = path_uri_encode(uri, pool);
- }
- return uri;
- }
- // We decided against using apr_filepath_root here because of the negative
- // performance impact (creating a pool and converting strings ).
- static bool
- dirent_is_root(
- const char * dirent,
- apr_size_t len)
- {
- // On Windows and Cygwin, 'H:' or 'H:/' (where 'H' is any letter)
- // are also root directories
- if ((len == 2 || ((len == 3) && (dirent[2] == '/'))) &&
- (dirent[1] == ':') &&
- IsLetter(dirent[0]))
- return TRUE;
- // On Windows and Cygwin //server/share is a root directory,
- // and on Cygwin //drive is a drive alias
- if ((len >= 2) && (dirent[0] == '/') && (dirent[1] == '/') &&
- (dirent[len - 1] != '/'))
- {
- int segments = 0;
- for (size_t i = len; i >= 2; i--)
- {
- if (dirent[i] == '/')
- {
- segments++;
- if (segments > 1)
- return FALSE;
- }
- }
- return (segments == 1); // //drive is invalid on plain Windows
- }
- // directory is root if it's equal to '/'
- if ((len == 1) && (dirent[0] == '/'))
- return TRUE;
- return FALSE;
- }
- static bool
- relpath_is_canonical(
- const char * relpath)
- {
- const char * ptr = relpath, *seg = relpath;
- // RELPATH is canonical if it has:
- // - no '.' segments
- // - no start and closing '/'
- // - no '//'
- if (*relpath == '\0')
- return TRUE;
- if (*ptr == '/')
- return FALSE;
- // Now validate the rest of the path.
- while (1)
- {
- apr_size_t seglen = ptr - seg;
- if ((seglen == 1) && (*seg == '.'))
- return FALSE; // /./
- if ((*ptr == '/') && (*(ptr+1) == '/'))
- return FALSE; // //
- if (!*ptr && (*(ptr - 1) == '/'))
- return FALSE; // foo/
- if (!*ptr)
- break;
- if (*ptr == '/')
- ptr++;
- seg = ptr;
- while (*ptr && (*ptr != '/'))
- ptr++;
- }
- return TRUE;
- }
- static const char *
- relpath_basename(
- const char * relpath,
- apr_pool_t * pool)
- {
- apr_size_t len = strlen(relpath);
- apr_size_t start = 0;
- assert(relpath_is_canonical(relpath));
- start = len;
- while ((start > 0) && (relpath[start - 1] != '/'))
- --start;
- if (pool)
- return apr_pstrmemdup(pool, relpath + start, len - start);
- else
- return relpath + start;
- }
- static char *
- relpath_join(
- const char * base,
- const char * component,
- apr_pool_t * pool)
- {
- apr_size_t blen = strlen(base);
- apr_size_t clen = strlen(component);
- char * path = NULL;
- assert(relpath_is_canonical(base));
- assert(relpath_is_canonical(component));
- // If either is empty return the other
- if (blen == 0)
- return static_cast<char *>(apr_pmemdup(pool, component, clen + 1));
- if (clen == 0)
- return static_cast<char *>(apr_pmemdup(pool, base, blen + 1));
- path = static_cast<char *>(apr_pcalloc(pool, blen + 1 + clen + 1));
- memcpy(path, base, blen);
- path[blen] = '/';
- memcpy(path + blen + 1, component, clen + 1);
- return path;
- }
- static const char *
- dirent_canonicalize(
- const char * dirent,
- apr_pool_t * pool)
- {
- const char * dst = canonicalize(type_dirent, dirent, pool);
- // Handle a specific case on Windows where path == "X:/". Here we have to
- // append the final '/', as path_canonicalize will chop this of.
- if (IsLetter(dirent[0]) &&
- (dirent[1] == ':') && (dirent[2] == '/') &&
- (dst[3] == '\0'))
- {
- char * dst_slash = static_cast<char *>(apr_pcalloc(pool, 4));
- dst_slash[0] = canonicalize_to_upper(dirent[0]);
- dst_slash[1] = ':';
- dst_slash[2] = '/';
- dst_slash[3] = '\0';
- return dst_slash;
- }
- return dst;
- }
- static bool
- dirent_is_canonical(
- const char * dirent,
- apr_pool_t * pool)
- {
- const char * ptr = dirent;
- if (*ptr == '/')
- {
- ptr++;
- // Check for UNC paths
- if (*ptr == '/')
- {
- // TODO: Scan hostname and sharename and fall back to part code
- // Fall back to old implementation
- return (strcmp(dirent, dirent_canonicalize(dirent, pool)) == 0);
- }
- }
- else if (IsLetter(*ptr) &&
- (ptr[1] == ':'))
- {
- // The only canonical drive names are "A:"..."Z:", no lower case
- if (!IsUpperCaseLetter(*ptr))
- return FALSE;
- ptr += 2;
- if (*ptr == '/')
- ptr++;
- }
- return relpath_is_canonical(ptr);
- }
- static const char *
- dirent_basename(
- const char * dirent,
- apr_pool_t * pool)
- {
- apr_size_t len = strlen(dirent);
- apr_size_t start = 0;
- assert(!pool || dirent_is_canonical(dirent, pool));
- if (dirent_is_root(dirent, len))
- {
- return "";
- }
- else
- {
- start = len;
- while ((start > 0) && (dirent[start - 1] != '/') &&
- (dirent[start - 1] != ':'))
- {
- --start;
- }
- }
- if (pool)
- return apr_pstrmemdup(pool, dirent + start, len - start);
- else
- return dirent + start;
- }
- static const char *
- uri_skip_ancestor(
- const char * parent_uri,
- const char * child_uri)
- {
- apr_size_t len = strlen(parent_uri);
- if (0 != strncmp(parent_uri, child_uri, len))
- return NULL; // parent_uri is no ancestor of child_uri
- if (child_uri[len] == 0)
- return ""; // parent_uri == child_uri
- if (child_uri[len] == '/')
- return child_uri + len + 1;
- return NULL;
- }
- static const char *
- uri_skip_ancestor(
- const char * parent_uri,
- const char * child_uri,
- apr_pool_t * result_pool)
- {
- const char * result = uri_skip_ancestor(parent_uri, child_uri);
- return result ? path_uri_decode(result, result_pool) : NULL;
- }
- static bool
- dirent_is_rooted(
- const char * dirent)
- {
- if (!dirent)
- return FALSE;
- // Root on all systems
- if (dirent[0] == '/')
- return TRUE;
- // On Windows, dirent is also absolute when it starts with 'H:' or 'H:/'
- // where 'H' is any letter.
- if (IsLetter(dirent[0]) &&
- (dirent[1] == ':'))
- {
- return TRUE;
- }
- return FALSE;
- }
- static const char *
- is_child(
- path_type_t type,
- const char * path1,
- const char * path2,
- apr_pool_t * pool)
- {
- apr_size_t i = 0;
- // Allow "" and "foo" or "H:foo" to be parent/child
- if (WEBDAV_PATH_IS_EMPTY(path1)) // "" is the parent
- {
- if (WEBDAV_PATH_IS_EMPTY(path2)) // "" not a child
- {
- return NULL;
- }
- // check if this is an absolute path
- if ((type == type_uri) ||
- (type == type_dirent && dirent_is_rooted(path2)))
- {
- return NULL;
- }
- else
- {
- // everything else is child
- return pool ? apr_pstrdup(pool, path2) : path2;
- }
- }
- for (i = 0; path1[i] && path2[i]; i++)
- if (path1[i] != path2[i])
- {
- return NULL;
- }
- /* FIXME: This comment does not really match
- the checks made in the code it refers to:
- There are two cases that are parent/child
- ... path1[i] == '\0'
- .../foo path2[i] == '/'
- or
- / path1[i] == '\0'
- /foo path2[i] != '/'
- Other root paths (like X:/) fall under the former case:
- X:/ path1[i] == '\0'
- X:/foo path2[i] != '/'
- Check for '//' to avoid matching '/' and '//srv'.
- */
- if ((path1[i] == '\0') && path2[i])
- {
- if ((path1[i - 1] == '/') ||
- ((type == type_dirent) && path1[i - 1] == ':'))
- {
- if (path2[i] == '/')
- /* .../
- * ..../
- * i */
- return NULL;
- else
- /* .../
- * .../foo
- * i */
- return pool ? apr_pstrdup(pool, path2 + i) : path2 + i;
- }
- else if (path2[i] == '/')
- {
- if (path2[i + 1])
- /* ...
- * .../foo
- * i */
- return pool ? apr_pstrdup(pool, path2 + i + 1) : path2 + i + 1;
- else
- /* ...
- * .../
- * i */
- return NULL;
- }
- }
- // Otherwise, path2 isn't a child.
- return NULL;
- }
- static const char *
- uri_is_child(
- const char * parent_uri,
- const char * child_uri,
- apr_pool_t * pool)
- {
- const char * relpath = NULL;
- assert(pool); // hysterical raisins.
- relpath = is_child(type_uri, parent_uri, child_uri, pool);
- if (relpath)
- relpath = path_uri_decode(relpath, pool);
- return relpath;
- }
- static bool
- dirent_is_absolute(
- const char * dirent)
- {
- if (!dirent)
- return FALSE;
- // dirent is absolute if it starts with '/' on non-Windows platforms
- // or with '//' on Windows platforms
- if ((dirent[0] == '/') &&
- (dirent[1] == '/')) // Single '/' depends on current drive
- {
- return TRUE;
- }
- // On Windows, dirent is also absolute when it starts with 'H:/'
- // where 'H' is any letter.
- if (IsUpperCaseLetter(dirent[0]) &&
- (dirent[1] == ':') && (dirent[2] == '/'))
- {
- return TRUE;
- }
- return FALSE;
- }
- static error_t
- dirent_get_absolute(
- const char ** pabsolute,
- const char * relative,
- apr_pool_t * pool)
- {
- char * buffer = NULL;
- apr_status_t apr_err = 0;
- const char * path_apr = NULL;
- WEBDAV_ERR_ASSERT(!path_is_url(relative));
- // Merge the current working directory with the relative dirent.
- WEBDAV_ERR(path_cstring_from_utf8(&path_apr, relative, pool));
- apr_err = apr_filepath_merge(&buffer, NULL,
- path_apr,
- APR_FILEPATH_NOTRELATIVE,
- pool);
- if (apr_err)
- {
- // In some cases when the passed path or its ancestor(s) do not exist
- // or no longer exist apr returns an error.
- // In many of these cases we would like to return a path anyway, when the
- // passed path was already a safe absolute path. So check for that now to
- // avoid an error.
- // dirent_is_absolute() doesn't perform the necessary checks to see
- // if the path doesn't need post processing to be in the canonical absolute
- // format.
- if (dirent_is_absolute(relative) &&
- dirent_is_canonical(relative, pool) &&
- !path_is_backpath_present(relative))
- {
- *pabsolute = apr_pstrdup(pool, relative);
- return WEBDAV_NO_ERROR;
- }
- return error_createf(WEBDAV_ERR_BAD_FILENAME,
- NULL,
- "Couldn't determine absolute path of '%s'", relative);
- }
- WEBDAV_ERR(path_cstring_to_utf8(pabsolute, buffer, pool));
- *pabsolute = dirent_canonicalize(*pabsolute, pool);
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from atomic.c
- #define atomic_t apr_uint32_t
- // Magic values for atomic initialization
- #define WEBDAV_ATOMIC_UNINITIALIZED 0
- #define WEBDAV_ATOMIC_START_INIT 1
- #define WEBDAV_ATOMIC_INIT_FAILED 2
- #define WEBDAV_ATOMIC_INITIALIZED 3
- static error_t
- atomic_init_once(
- volatile atomic_t * global_status,
- error_t (*init_func)(void *,apr_pool_t *),
- void * baton,
- apr_pool_t * pool)
- {
- // We have to call init_func exactly once. Because APR
- // doesn't have statically-initialized mutexes, we implement a poor
- // man's spinlock using atomic_cas.
- atomic_t status = apr_atomic_cas32(global_status,
- WEBDAV_ATOMIC_START_INIT,
- WEBDAV_ATOMIC_UNINITIALIZED);
- if (status == WEBDAV_ATOMIC_UNINITIALIZED)
- {
- error_t err = init_func(baton, pool);
- if (err)
- {
- #if APR_HAS_THREADS
- // Tell other threads that the initialization failed.
- apr_atomic_cas32(global_status,
- WEBDAV_ATOMIC_INIT_FAILED,
- WEBDAV_ATOMIC_START_INIT);
- #endif
- return error_create(WEBDAV_ERR_ATOMIC_INIT_FAILURE, &err,
- "Couldn't perform atomic initialization");
- }
- apr_atomic_cas32(global_status,
- WEBDAV_ATOMIC_INITIALIZED,
- WEBDAV_ATOMIC_START_INIT);
- }
- #if APR_HAS_THREADS
- // Wait for whichever thread is performing initialization to finish.
- // XXX FIXME: Should we have a maximum wait here, like we have in
- // the Windows file IO spinner?
- else while (status != WEBDAV_ATOMIC_INITIALIZED)
- {
- if (status == WEBDAV_ATOMIC_INIT_FAILED)
- return error_create(WEBDAV_ERR_ATOMIC_INIT_FAILURE, NULL,
- "Couldn't perform atomic initialization");
- apr_sleep(APR_USEC_PER_SEC / 1000);
- status = apr_atomic_cas32(global_status,
- WEBDAV_ATOMIC_UNINITIALIZED,
- WEBDAV_ATOMIC_UNINITIALIZED);
- }
- #endif // APR_HAS_THREADS
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from io.c
- #define RETRY_MAX_ATTEMPTS 2
- #define RETRY_INITIAL_SLEEP 1000
- #define RETRY_MAX_SLEEP 128000
- // Suppress warning: Condition is always true
- #pragma warn -8008
- #define RETRY_LOOP(err, expr, retry_test, sleep_test) \
- do \
- { \
- apr_status_t os_err = APR_TO_OS_ERROR(err); \
- int sleep_count = RETRY_INITIAL_SLEEP; \
- int retries; \
- for (retries = 0; \
- retries < RETRY_MAX_ATTEMPTS && (retry_test); \
- os_err = APR_TO_OS_ERROR(err)) \
- { \
- if (sleep_test) \
- { \
- ++retries; \
- apr_sleep(sleep_count); \
- if (sleep_count < RETRY_MAX_SLEEP) \
- sleep_count *= 2; \
- } \
- (err) = (expr); \
- } \
- } \
- while (0)
- #if defined(EDEADLK) && APR_HAS_THREADS
- #define FILE_LOCK_RETRY_LOOP(err, expr) \
- RETRY_LOOP(err, \
- expr, \
- (APR_STATUS_IS_EINTR(err) || os_err == EDEADLK), \
- (!APR_STATUS_IS_EINTR(err)))
- #else
- #define FILE_LOCK_RETRY_LOOP(err, expr) \
- RETRY_LOOP(err, \
- expr, \
- (APR_STATUS_IS_EINTR(err)), \
- 0)
- #endif
- #ifndef WIN32_RETRY_LOOP
- #if !defined(WEBDAV_NO_WIN32_RETRY_LOOP)
- #define WIN32_RETRY_LOOP(err, expr) \
- RETRY_LOOP(err, expr, (os_err == ERROR_ACCESS_DENIED || \
- os_err == ERROR_SHARING_VIOLATION || \
- os_err == ERROR_DIR_NOT_EMPTY), \
- 1)
- #else
- #define WIN32_RETRY_LOOP(err, expr) ((void)0)
- #endif
- #endif
- // Not specifying any of these means no removal at all.
- typedef enum io_file_del_t
- {
- // No deletion ever
- io_file_del_none = 0,
- // Remove when the file is closed
- io_file_del_on_close,
- // Remove when the associated pool is cleared
- io_file_del_on_pool_cleanup
- } io_file_del_t;
- // Wrapper for apr_file_open(), taking an APR-encoded filename.
- static apr_status_t
- file_open(
- apr_file_t ** file,
- const char * fname_apr,
- apr_int32_t flags,
- apr_fileperms_t perm,
- bool retry_on_failure,
- apr_pool_t * pool)
- {
- apr_status_t status = apr_file_open(file, fname_apr, flags, perm, pool);
- if (retry_on_failure)
- {
- WIN32_RETRY_LOOP(status, apr_file_open(file, fname_apr, flags, perm, pool));
- }
- return status;
- }
- #pragma warn +8008
- static error_t
- io_file_open(
- apr_file_t ** new_file,
- const char * fname,
- apr_int32_t flags,
- apr_fileperms_t perms,
- apr_pool_t * pool)
- {
- const char * fname_apr = NULL;
- apr_status_t status = 0;
- WEBDAV_ERR(cstring_from_utf8(&fname_apr, fname, pool));
- status = file_open(new_file, fname_apr, flags | APR_BINARY, perms,
- /* retry_on_failure */ FALSE,
- pool);
- if (status)
- return error_wrap_apr(status, "Can't open file '%s'", fname);
- else
- return WEBDAV_NO_ERROR;
- }
- static error_t
- io_file_open_writable(
- apr_file_t ** new_file,
- apr_os_file_t * thefile,
- apr_int32_t flags,
- apr_pool_t * pool)
- {
- apr_status_t status = 0;
- status = apr_os_file_put(new_file, thefile,
- flags | APR_BINARY,
- pool);
- if (status)
- return error_wrap_apr(status, "Can't open file");
- else
- return WEBDAV_NO_ERROR;
- }
- // Wrapper for apr_file_name_get(), passing out a UTF8-encoded filename.
- static error_t
- io_file_name_get(
- const char ** filename,
- apr_file_t * file,
- apr_pool_t * pool)
- {
- const char * fname_apr = NULL;
- apr_status_t status = 0;
- status = apr_file_name_get(&fname_apr, file);
- if (status)
- return error_wrap_apr(status, "Can't get file name");
- if (fname_apr)
- WEBDAV_ERR(path_cstring_to_utf8(filename, fname_apr, pool));
- else
- *filename = NULL;
- return WEBDAV_NO_ERROR;
- }
- static APR_INLINE error_t
- do_io_file_wrapper_cleanup(
- apr_file_t * file,
- apr_status_t status,
- const char * msg,
- const char * msg_no_name,
- apr_pool_t * pool)
- {
- const char * name = NULL;
- error_t err = 0;
- if (!status)
- return WEBDAV_NO_ERROR;
- err = io_file_name_get(&name, file, pool);
- if (err)
- name = NULL;
- error_clear(&err);
- // Issue #3014: Return a specific error for broken pipes,
- // with a single element in the error chain.
- if (APR_STATUS_IS_EPIPE(status))
- return error_create(WEBDAV_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
- if (name)
- return error_wrap_apr(status, msg, name);
- else
- return error_wrap_apr(status, "%s", msg_no_name);
- }
- static error_t
- io_file_close(
- apr_file_t * file,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_close(file),
- "Can't close file '%s'",
- "Can't close stream",
- pool);
- }
- static error_t
- io_file_getc(
- char * ch,
- apr_file_t * file,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_getc(ch, file),
- "Can't read file '%s'",
- "Can't read stream",
- pool);
- }
- static error_t
- io_file_write_full(
- apr_file_t * file,
- const void * buf,
- apr_size_t nbytes,
- apr_size_t * bytes_written,
- apr_pool_t * pool)
- {
- // We cannot simply call apr_file_write_full on Win32 as it may fail
- // for larger values of NBYTES. In that case, we have to emulate the
- // "_full" part here. Thus, always call apr_file_write directly on
- // Win32 as this minimizes overhead for small data buffers.
- #define MAXBUFSIZE 64*1024
- apr_size_t bw = nbytes;
- apr_size_t to_write = nbytes;
- // try a simple "write everything at once" first
- apr_status_t rv = apr_file_write(file, buf, &bw);
- buf = (char *)buf + bw;
- to_write -= bw;
- // if the OS cannot handle that, use smaller chunks
- if ((rv == APR_FROM_OS_ERROR(ERROR_NOT_ENOUGH_MEMORY)) &&
- (nbytes > MAXBUFSIZE))
- {
- do
- {
- bw = to_write > MAXBUFSIZE ? MAXBUFSIZE : to_write;
- rv = apr_file_write(file, buf, &bw);
- buf = (char *)buf + bw;
- to_write -= bw;
- }
- while (rv == APR_SUCCESS && to_write > 0);
- }
- // bytes_written may actually be NULL
- if (bytes_written)
- *bytes_written = nbytes - to_write;
- #undef MAXBUFSIZE
- return error_trace(do_io_file_wrapper_cleanup(file, rv,
- "Can't write to file '%s'",
- "Can't write to stream",
- pool));
- }
- static error_t
- io_file_seek(
- apr_file_t * file,
- apr_seek_where_t where,
- apr_off_t * offset,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_seek(file, where, offset),
- "Can't set position pointer in file '%s'",
- "Can't set position pointer in stream",
- pool);
- }
- static error_t
- io_file_putc(
- char ch,
- apr_file_t * file,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_putc(ch, file),
- "Can't write file '%s'",
- "Can't write stream",
- pool);
- }
- static error_t
- io_file_read(
- apr_file_t * file,
- void * buf,
- apr_size_t * nbytes,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_read(file, buf, nbytes),
- "Can't read file '%s'",
- "Can't read stream",
- pool);
- }
- // Local wrapper of path_cstring_from_utf8() that does no copying on
- // operating systems where APR always uses utf-8 as native path format
- static error_t
- cstring_from_utf8(
- const char ** path_apr,
- const char * path_utf8,
- apr_pool_t * pool)
- {
- *path_apr = path_utf8;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- io_file_read_full2(
- apr_file_t * file,
- void * buf,
- apr_size_t nbytes,
- apr_size_t * bytes_read,
- bool * hit_eof,
- apr_pool_t * pool)
- {
- apr_status_t status = apr_file_read_full(file, buf, nbytes, bytes_read);
- if (hit_eof)
- {
- if (APR_STATUS_IS_EOF(status))
- {
- *hit_eof = TRUE;
- return WEBDAV_NO_ERROR;
- }
- else
- *hit_eof = FALSE;
- }
- return do_io_file_wrapper_cleanup(file, status,
- "Can't read file '%s'",
- "Can't read stream",
- pool);
- }
- //------------------------------------------------------------------------------
- // from svn_io.h
- // Read handler function for a generic stream. see stream_t.
- typedef error_t (*read_fn_t)(
- void * baton,
- char * buffer,
- apr_size_t * len);
- // Skip data handler function for a generic stream. see stream_t
- // and stream_skip().
- typedef error_t (*stream_skip_fn_t)(
- void * baton,
- apr_size_t len);
- // Write handler function for a generic stream. see stream_t.
- typedef error_t (*write_fn_t)(
- void * baton,
- const char * data,
- apr_size_t * len);
- // Close handler function for a generic stream. see stream_t.
- typedef error_t (*close_fn_t)(void * baton);
- typedef struct stream_mark_t stream_mark_t;
- typedef error_t (*stream_mark_fn_t)(
- void * baton,
- stream_mark_t ** mark,
- apr_pool_t * pool);
- typedef error_t (*stream_seek_fn_t)(
- void * baton,
- const stream_mark_t * mark);
- typedef bool (*stream_is_buffered_fn_t)(void * baton);
- //------------------------------------------------------------------------------
- // from stream.c
- typedef struct stream_t
- {
- void * baton;
- read_fn_t read_fn;
- stream_skip_fn_t skip_fn;
- write_fn_t write_fn;
- close_fn_t close_fn;
- stream_mark_fn_t mark_fn;
- stream_seek_fn_t seek_fn;
- stream_is_buffered_fn_t is_buffered_fn;
- } stream_t;
- // Generic stream for APR files
- struct baton_apr_t
- {
- apr_file_t * file;
- apr_pool_t * pool;
- };
- // stream_mark_t for streams backed by APR files.
- struct mark_apr_t
- {
- apr_off_t off;
- };
- static error_t
- read_handler_apr(
- void * baton,
- char * buffer,
- apr_size_t * len)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- error_t err = 0;
- bool eof = FALSE;
- if (*len == 1)
- {
- err = io_file_getc(buffer, btn->file, btn->pool);
- if (err)
- {
- *len = 0;
- if (APR_STATUS_IS_EOF(err))
- {
- error_clear(&err);
- err = WEBDAV_NO_ERROR;
- }
- }
- }
- else
- err = io_file_read_full2(btn->file, buffer, *len, len,
- &eof, btn->pool);
- return err;
- }
- static error_t
- skip_handler_apr(
- void * baton,
- apr_size_t len)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- apr_off_t offset = len;
- return io_file_seek(btn->file, APR_CUR, &offset, btn->pool);
- }
- static error_t
- write_handler_apr(
- void * baton,
- const char * data,
- apr_size_t * len)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- error_t err = 0;
- if (*len == 1)
- {
- err = io_file_putc(*data, btn->file, btn->pool);
- if (err)
- *len = 0;
- }
- else
- err = io_file_write_full(btn->file, data, *len, len, btn->pool);
- return err;
- }
- static error_t
- close_handler_apr(
- void * baton)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- return io_file_close(btn->file, btn->pool);
- }
- static error_t
- mark_handler_apr(
- void * baton,
- stream_mark_t ** mark,
- apr_pool_t * pool)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- struct mark_apr_t * mark_apr = 0;
- mark_apr = static_cast<mark_apr_t *>(apr_pcalloc(pool, sizeof(*mark_apr)));
- mark_apr->off = 0;
- WEBDAV_ERR(io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool));
- *mark = (stream_mark_t *)mark_apr;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- seek_handler_apr(
- void * baton,
- const stream_mark_t * mark)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- apr_off_t offset = (mark != NULL) ? ((const struct mark_apr_t *)mark)->off : 0;
- WEBDAV_ERR(io_file_seek(btn->file, APR_SET, &offset, btn->pool));
- return WEBDAV_NO_ERROR;
- }
- static bool
- is_buffered_handler_apr(
- void * baton)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0;
- }
- static stream_t *
- stream_create(
- void * baton,
- apr_pool_t * pool)
- {
- stream_t * stream = static_cast<stream_t *>(apr_pcalloc(pool, sizeof(*stream)));
- stream->baton = baton;
- stream->read_fn = NULL;
- stream->skip_fn = NULL;
- stream->write_fn = NULL;
- stream->close_fn = NULL;
- stream->mark_fn = NULL;
- stream->seek_fn = NULL;
- stream->is_buffered_fn = NULL;
- return stream;
- }
- static void
- stream_set_read(
- stream_t * stream,
- read_fn_t read_fn)
- {
- stream->read_fn = read_fn;
- }
- static void
- stream_set_skip(
- stream_t * stream,
- stream_skip_fn_t skip_fn)
- {
- stream->skip_fn = skip_fn;
- }
- static void
- stream_set_write(
- stream_t * stream,
- write_fn_t write_fn)
- {
- stream->write_fn = write_fn;
- }
- static void
- stream_set_close(
- stream_t * stream,
- close_fn_t close_fn)
- {
- stream->close_fn = close_fn;
- }
- static void
- stream_set_mark(
- stream_t * stream,
- stream_mark_fn_t mark_fn)
- {
- stream->mark_fn = mark_fn;
- }
- static void
- stream_set_seek(
- stream_t * stream,
- stream_seek_fn_t seek_fn)
- {
- stream->seek_fn = seek_fn;
- }
- static void
- stream_set_is_buffered(
- stream_t * stream,
- stream_is_buffered_fn_t is_buffered_fn)
- {
- stream->is_buffered_fn = is_buffered_fn;
- }
- static error_t
- read_handler_empty(
- void * baton,
- char * buffer,
- apr_size_t * len)
- {
- *len = 0;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- write_handler_empty(
- void * baton,
- const char * data,
- apr_size_t * len)
- {
- return WEBDAV_NO_ERROR;
- }
- static error_t
- mark_handler_empty(
- void * baton,
- stream_mark_t ** mark,
- apr_pool_t * pool)
- {
- *mark = NULL; // Seek to start of stream marker
- return WEBDAV_NO_ERROR;
- }
- static error_t
- seek_handler_empty(
- void * baton,
- const stream_mark_t * mark)
- {
- return WEBDAV_NO_ERROR;
- }
- static bool
- is_buffered_handler_empty(void * baton)
- {
- return FALSE;
- }
- static stream_t *
- stream_empty(
- apr_pool_t * pool)
- {
- stream_t * stream = stream_create(NULL, pool);
- stream_set_read(stream, read_handler_empty);
- stream_set_write(stream, write_handler_empty);
- stream_set_mark(stream, mark_handler_empty);
- stream_set_seek(stream, seek_handler_empty);
- stream_set_is_buffered(stream, is_buffered_handler_empty);
- return stream;
- }
- static stream_t *
- stream_from_aprfile2(
- apr_file_t * file,
- bool disown,
- apr_pool_t * pool)
- {
- stream_t * stream = NULL;
- if (file == NULL)
- return stream_empty(pool);
- baton_apr_t * baton = static_cast<baton_apr_t *>(apr_pcalloc(pool, sizeof(*baton)));
- baton->file = file;
- baton->pool = pool;
- stream = stream_create(baton, pool);
- stream_set_read(stream, read_handler_apr);
- stream_set_write(stream, write_handler_apr);
- stream_set_skip(stream, skip_handler_apr);
- stream_set_mark(stream, mark_handler_apr);
- stream_set_seek(stream, seek_handler_apr);
- stream_set_is_buffered(stream, is_buffered_handler_apr);
- if (!disown)
- stream_set_close(stream, close_handler_apr);
- return stream;
- }
- static error_t
- stream_open_writable(
- stream_t ** stream,
- apr_os_file_t * thefile,
- apr_pool_t * result_pool,
- apr_pool_t * scratch_pool)
- {
- apr_file_t * file = NULL;
- WEBDAV_ERR(io_file_open_writable(&file,
- thefile,
- APR_WRITE
- | APR_BUFFERED
- | APR_BINARY
- | APR_CREATE,
- // | APR_EXCL,
- result_pool));
- *stream = stream_from_aprfile2(file, FALSE, result_pool);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- stream_write(
- stream_t * stream,
- const char * data,
- apr_size_t * len)
- {
- WEBDAV_ERR_ASSERT(stream->write_fn != NULL);
- return stream->write_fn(stream->baton, data, len);
- }
- static error_t
- stream_close(
- stream_t * stream)
- {
- if (stream->close_fn == NULL)
- return WEBDAV_NO_ERROR;
- return stream->close_fn(stream->baton);
- }
- //------------------------------------------------------------------------------
- // from util.c
- static apr_status_t
- dav_request_cleanup(
- void * baton);
- static apr_status_t
- dav_request_sess_cleanup(
- void * baton)
- {
- neon_request_t * req = static_cast<neon_request_t *>(baton);
- // Make sure we don't run the 'child' cleanup anymore:
- // the pool it refers to probably doesn't exist anymore when it
- // finally does get run if it hasn't by now.
- apr_pool_cleanup_kill(req->pool, req, dav_request_cleanup);
- if (req->ne_req)
- ne_request_destroy(req->ne_req);
- return APR_SUCCESS;
- }
- static apr_status_t
- dav_request_cleanup(
- void * baton)
- {
- neon_request_t * req = static_cast<neon_request_t *>(baton);
- apr_pool_cleanup_run(req->sess->pool, req, dav_request_sess_cleanup);
- return APR_SUCCESS;
- }
- // Return a path-absolute relative URL, given a URL reference (which may
- // be absolute or relative).
- static const char *
- path_from_url(
- const char * url)
- {
- const char * p = NULL;
- // Look for the scheme/authority separator. Stop if we see a path
- // separator - that indicates that this definitely isn't an absolute URL.
- for (p = url; *p; p++)
- {
- if ((*p == ':') || (*p == '/'))
- break;
- }
- // Check whether we found the scheme/authority separator.
- if ((*p++ != ':') || (*p++ != '/') || (*p++ != '/'))
- {
- // No separator, so it must already be relative.
- return url;
- }
- // Find the end of the authority section, indicated by the start of
- // a path, query, or fragment section.
- for (; *p; p++)
- {
- if ((*p == '/') || (*p == '?') || (*p == '#'))
- break;
- }
- // Return a pointer to the rest of the URL, or to "/" if there
- // was no next section.
- return *p == '\0' ? "/" : p;
- }
- // Simple multi-status parser
- // For the purpose of 'simple' requests which - if it weren't
- // for our custom error parser - could use the ne_basic.h interfaces.
- // List of XML elements expected in 207 Multi-Status responses.
- static const neon_xml_elm_t multistatus_elements[] =
- {
- { "DAV:", "multistatus", ELEM_multistatus, 0 },
- { "DAV:", "response", ELEM_response, 0 },
- {
- "DAV:", "responsedescription", ELEM_responsedescription,
- NEON_XML_CDATA
- },
- { "DAV:", "status", ELEM_status, NEON_XML_CDATA },
- { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
- { "DAV:", "propstat", ELEM_propstat, NEON_XML_CDATA },
- { "DAV:", "prop", ELEM_prop, NEON_XML_CDATA },
- // We start out basic and are not interested in other elements
- { "", "", ELEM_unknown, 0 },
- { NULL }
- };
- static const int multistatus_nesting_table[][5] =
- {
- { ELEM_root, ELEM_multistatus, NEON_XML_INVALID },
- {
- ELEM_multistatus, ELEM_response, ELEM_responsedescription,
- NEON_XML_DECLINE
- },
- { ELEM_responsedescription, NEON_XML_INVALID },
- {
- ELEM_response, ELEM_href, ELEM_status, ELEM_propstat,
- NEON_XML_DECLINE
- },
- { ELEM_status, NEON_XML_INVALID },
- { ELEM_href, NEON_XML_INVALID },
- {
- ELEM_propstat, ELEM_prop, ELEM_status, ELEM_responsedescription,
- NEON_XML_INVALID
- },
- { ELEM_prop, NEON_XML_DECLINE },
- { NEON_XML_DECLINE },
- };
- static int
- multistatus_validate_element(
- int parent,
- int child)
- {
- int i = 0;
- int j = 0;
- while ((parent != multistatus_nesting_table[i][0]) &&
- (multistatus_nesting_table[i][0] > 0 || i == 0))
- i++;
- if (parent == multistatus_nesting_table[i][0])
- while ((multistatus_nesting_table[i][++j] != child) &&
- (multistatus_nesting_table[i][j] > 0))
- ;
- return multistatus_nesting_table[i][j];
- }
- typedef struct multistatus_baton_t
- {
- stringbuf_t * want_cdata;
- stringbuf_t * cdata;
- bool in_propstat;
- bool propstat_has_error;
- stringbuf_t * propname;
- stringbuf_t * propstat_description;
- neon_request_t * req;
- stringbuf_t * description;
- bool contains_error;
- bool contains_precondition_error;
- } multistatus_baton_t;
- // Implements neon_startelm_cb_t.
- static error_t
- start_207_element(
- int * elem,
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- multistatus_baton_t * b = static_cast<multistatus_baton_t *>(baton);
- const neon_xml_elm_t * elm =
- neon_lookup_xml_elem(multistatus_elements, nspace, name);
- *elem = elm ? multistatus_validate_element(parent, elm->id) : NEON_XML_DECLINE;
- if (parent == ELEM_prop)
- {
- stringbuf_setempty(b->propname);
- if (strcmp(nspace, "DAV:") == 0)
- stringbuf_set(b->propname, "DAV:");
- stringbuf_appendcstr(b->propname, name);
- }
- if (*elem < 1) // ! > 0
- return WEBDAV_NO_ERROR;
- switch (*elem)
- {
- case ELEM_propstat:
- b->in_propstat = TRUE;
- b->propstat_has_error = FALSE;
- break;
- default:
- break;
- }
- // We're guaranteed to have ELM now: NEON_XML_DECLINE < 1
- if (elm->flags & NEON_XML_CDATA)
- {
- stringbuf_setempty(b->cdata);
- b->want_cdata = b->cdata;
- }
- return WEBDAV_NO_ERROR;
- }
- // Implements neon_endelm_cb_t
- static error_t
- end_207_element(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- multistatus_baton_t * b = static_cast<multistatus_baton_t *>(baton);
- switch (state)
- {
- case ELEM_multistatus:
- if (b->contains_error)
- {
- if (stringbuf_isempty(b->description))
- return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
- "The request response contained at least one error");
- else if (b->contains_precondition_error)
- return error_create(WEBDAV_ERR_FS_PROP_BASEVALUE_MISMATCH, NULL,
- b->description->data);
- else
- return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
- b->description->data);
- }
- break;
- case ELEM_responsedescription:
- if (b->in_propstat)
- stringbuf_set(b->propstat_description, b->cdata->data);
- else
- {
- if (!stringbuf_isempty(b->description))
- stringbuf_appendcstr(b->description, "\n");
- stringbuf_appendstr(b->description, b->cdata);
- }
- break;
- case ELEM_status:
- {
- ne_status status;
- if (ne_parse_statusline(b->cdata->data, &status) == 0)
- {
- // I wanted ||=, but I guess the end result is the same
- if (!b->in_propstat)
- b->contains_error |= (status.klass != 2);
- else
- b->propstat_has_error = (status.klass != 2);
- // Handle "412 Precondition Failed" specially
- if (status.code == 412)
- b->contains_precondition_error = TRUE;
- ne_free(status.reason_phrase);
- }
- else
- return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
- "The response contains a non-conforming HTTP status line");
- }
- break;
- case ELEM_propstat:
- b->in_propstat = FALSE;
- b->contains_error |= b->propstat_has_error;
- stringbuf_appendcstr(b->description,
- apr_psprintf(b->req->pool,
- "Error setting property '%s': ",
- b->propname->data));
- stringbuf_appendstr(b->description,
- b->propstat_description);
- default:
- // do nothing
- break;
- }
- // When we have an element which wants cdata,
- // we'll set it all up in start_207_element() again
- b->want_cdata = NULL;
- return WEBDAV_NO_ERROR;
- }
- // Create a status parser attached to the request REQ. Detected errors
- // will be returned there.
- static void
- multistatus_parser_create(
- neon_request_t * req)
- {
- multistatus_baton_t * b = static_cast<multistatus_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
- // Create a parser, attached to REQ. (Ignore the return value.)
- neon_xml_parser_create(req, ne_accept_207,
- start_207_element,
- neon_xml_collect_cdata,
- end_207_element, b);
- b->cdata = stringbuf_create("", req->pool);
- b->description = stringbuf_create("", req->pool);
- b->req = req;
- b->propname = stringbuf_create("", req->pool);
- b->propstat_description = stringbuf_create("", req->pool);
- }
- static apr_status_t
- compressed_body_reader_cleanup(
- void * baton)
- {
- if (baton)
- ne_decompress_destroy(static_cast<ne_decompress *>(baton));
- return APR_SUCCESS;
- }
- // Attach READER as a response reader for the request REQ, with the
- // acceptance function ACCPT. The response body data will be decompressed,
- // if compressed, before being passed to READER. USERDATA will be passed as
- // the first argument to the acceptance and reader callbacks.
- static void
- attach_ne_body_reader(
- neon_request_t * req,
- ne_accept_response accpt,
- ne_block_reader reader,
- void * userdata)
- {
- if (req->sess->compression)
- {
- ne_decompress * decompress =
- ne_decompress_reader(req->ne_req, accpt, reader, userdata);
- apr_pool_cleanup_register(req->pool,
- decompress,
- compressed_body_reader_cleanup,
- apr_pool_cleanup_null);
- }
- else
- ne_add_response_body_reader(req->ne_req, accpt, reader, userdata);
- }
- typedef struct cancellation_baton_t
- {
- ne_block_reader real_cb;
- void * real_userdata;
- neon_request_t * req;
- } cancellation_baton_t;
- static int
- cancellation_callback(
- void * userdata,
- const char * block,
- size_t len)
- {
- cancellation_baton_t * b = static_cast<cancellation_baton_t *>(userdata);
- neon_session_t * ras = b->req->sess;
- if (ras->callbacks->cancel_func)
- {
- NEON_REQ_ERR(b->req, (ras->callbacks->cancel_func)(ras->callback_baton));
- }
- if (b->req->err)
- return 1;
- else
- return (b->real_cb)(b->real_userdata, block, len);
- }
- static cancellation_baton_t *
- get_cancellation_baton(
- neon_request_t * req,
- ne_block_reader real_cb,
- void * real_userdata,
- apr_pool_t * pool)
- {
- cancellation_baton_t * b = static_cast<cancellation_baton_t *>(apr_pcalloc(pool, sizeof(*b)));
- b->real_cb = real_cb;
- b->real_userdata = real_userdata;
- b->req = req;
- return b;
- }
- typedef struct body_provider_baton_t
- {
- neon_request_t * req;
- apr_file_t * body_file;
- } body_provider_baton_t;
- static ssize_t
- ra_neon_body_provider(
- void * userdata,
- char * buffer,
- size_t buflen)
- {
- body_provider_baton_t * b = static_cast<body_provider_baton_t *>(userdata);
- neon_request_t * req = b->req;
- apr_file_t * body_file = b->body_file;
- if (req->sess->callbacks &&
- req->sess->callbacks->cancel_func)
- {
- NEON_REQ_ERR(req, (req->sess->callbacks->cancel_func)(
- req->sess->callback_baton));
- }
- if (req->err)
- return -1;
- webdav_pool_clear(req->iterpool);
- if (buflen == 0)
- {
- // This is the beginning of a new body pull. Rewind the file.
- apr_off_t offset = 0;
- NEON_REQ_ERR(b->req, io_file_seek(body_file, APR_SET, &offset, req->iterpool));
- return (req->err ? -1 : 0);
- }
- else
- {
- callback_baton_t * cb = static_cast<callback_baton_t *>(req->sess->callback_baton);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- fs->AdjustToCPSLimit(buflen);
- apr_size_t nbytes = buflen;
- error_t err = io_file_read(body_file, buffer, &nbytes,
- req->iterpool);
- if (err)
- {
- if (APR_STATUS_IS_EOF(err))
- {
- error_clear(&err);
- return 0;
- }
- NEON_REQ_ERR(req, err);
- return -1;
- }
- else
- return (ssize_t)nbytes;
- }
- }
- static error_t
- neon_set_neon_body_provider(
- neon_request_t * req,
- apr_file_t * body_file)
- {
- apr_status_t status = 0;
- apr_finfo_t finfo = {0};
- body_provider_baton_t * b = static_cast<body_provider_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
- status = apr_file_info_get(&finfo, APR_FINFO_SIZE, body_file);
- if (status)
- return error_wrap_apr(status,
- "Can't calculate the request body size");
- b->body_file = body_file;
- b->req = req;
- ne_set_request_body_provider(req->ne_req, (ne_off_t)finfo.size,
- ra_neon_body_provider, b);
- return WEBDAV_NO_ERROR;
- }
- // See doc string for neon_parsed_request.
- static error_t
- parsed_request(
- neon_request_t * req,
- neon_session_t * ras,
- const char * method,
- const char * url,
- const char * body,
- apr_file_t * body_file,
- void set_parser(ne_xml_parser * parser, void * baton),
- neon_startelm_cb_t startelm_cb,
- neon_cdata_cb_t cdata_cb,
- neon_endelm_cb_t endelm_cb,
- void * baton,
- apr_hash_t * extra_headers,
- int * status_code,
- bool check_errors,
- apr_pool_t * pool)
- {
- ne_xml_parser * success_parser = NULL;
- if (body == NULL)
- WEBDAV_ERR(neon_set_neon_body_provider(req, body_file));
- // use a symbolic name somewhere for this MIME type?
- ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
- // create a parser to read the normal response body
- success_parser = neon_xml_parser_create(req, NULL,
- startelm_cb, cdata_cb,
- endelm_cb, baton);
- // if our caller is interested in having access to this parser, call
- // the SET_PARSER callback with BATON.
- if (set_parser != NULL)
- set_parser(success_parser, baton);
- // Register the "main" accepter and body-reader with the request --
- // the one to use when the HTTP status is 2XX.
- attach_ne_body_reader(req, ne_accept_2xx, cancellation_callback,
- get_cancellation_baton(req, ne_xml_parse_v,
- success_parser, pool));
- // run the request and get the resulting status code.
- WEBDAV_ERR(neon_request_dispatch(
- status_code, req, extra_headers, body,
- (strcmp(method, "PROPFIND") == 0) ? 207 : 200,
- 0,
- check_errors,
- pool));
- WEBDAV_ERR(neon_check_parse_error(method, success_parser, url));
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_parsed_request(
- neon_session_t * sess,
- const char * method,
- const char * url,
- const char * body,
- apr_file_t * body_file,
- void set_parser(ne_xml_parser * parser, void * baton),
- neon_startelm_cb_t startelm_cb,
- neon_cdata_cb_t cdata_cb,
- neon_endelm_cb_t endelm_cb,
- void * baton,
- apr_hash_t * extra_headers,
- int * status_code,
- bool check_errors,
- apr_pool_t * pool)
- {
- // create/prep the request
- neon_request_t * req = NULL;
- error_t err = 0;
- WEBDAV_ERR(neon_request_create(&req, sess, method, url, pool));
- err = parsed_request(req, sess, method, url, body, body_file,
- set_parser, startelm_cb, cdata_cb, endelm_cb,
- baton, extra_headers, status_code,
- check_errors,
- pool);
- neon_request_destroy(req);
- return err;
- }
- static error_t
- neon_simple_request(
- int * code,
- neon_session_t * ras,
- const char * method,
- const char * url,
- apr_hash_t * extra_headers,
- const char * body,
- int okay_1, int okay_2, apr_pool_t * pool)
- {
- neon_request_t * req = NULL;
- error_t err = 0;
- WEBDAV_ERR(neon_request_create(&req, ras, method, url, pool));
- multistatus_parser_create(req);
- // neon_request_dispatch() adds the custom error response
- // reader. Neon will take care of the Content-Length calculation
- err = neon_request_dispatch(code, req, extra_headers,
- body ? body : "",
- okay_1, okay_2, false, pool);
- neon_request_destroy(req);
- return err;
- }
- static void
- neon_add_depth_header(
- apr_hash_t * extra_headers,
- int depth)
- {
- assert(extra_headers != NULL);
- assert(depth == NEON_DEPTH_ZERO ||
- depth == NEON_DEPTH_ONE ||
- depth == NEON_DEPTH_INFINITE);
- apr_hash_set(extra_headers, "Depth", APR_HASH_KEY_STRING,
- (depth == NEON_DEPTH_INFINITE) ?
- "infinity" : (depth == NEON_DEPTH_ZERO) ? "0" : "1");
- return;
- }
- static const neon_xml_elm_t *
- neon_lookup_xml_elem(
- const neon_xml_elm_t * table,
- const char * nspace,
- const char * name)
- {
- // placeholder for `unknown' element if it's present
- const neon_xml_elm_t * elem_unknown = NULL;
- const neon_xml_elm_t * elem = NULL;
- for (elem = table; elem->nspace; ++elem)
- {
- if ((strcmp(elem->nspace, nspace) == 0) &&
- (strcmp(elem->name, name) == 0))
- return elem;
- // Use a single loop to save CPU cycles.
- // Maybe this element is defined as `unknown'?
- if (elem->id == ELEM_unknown)
- elem_unknown = elem;
- }
- // ELEM_unknown position in the table or NULL
- return elem_unknown;
- }
- static error_t
- neon_xml_collect_cdata(
- void * baton,
- int state,
- const char * cdata,
- size_t len)
- {
- stringbuf_t ** b = static_cast<stringbuf_t **>(baton);
- if (*b)
- stringbuf_appendbytes(*b, cdata, len);
- return WEBDAV_NO_ERROR;
- }
- // Custom function of type ne_accept_response.
- static int
- ra_neon_error_accepter(
- void * userdata,
- ne_request * req,
- const ne_status * st)
- {
- // Before, this function was being run for *all* responses including
- // the 401 auth challenge. In neon 0.24.x that was harmless. But
- // in neon 0.25.0, trying to parse a 401 response as XML using
- // ne_xml_parse_v aborts the response; so the auth hooks never got a
- // chance.
- ne_content_type ctype = {0};
- // Only accept non-2xx responses with text/xml content-type
- if (st->klass != 2 && ne_get_content_type(req, &ctype) == 0)
- {
- int is_xml = (strcmp(ctype.type, "text") == 0) &&
- (strcmp(ctype.subtype, "xml") == 0);
- ne_free(ctype.value);
- return is_xml;
- }
- else
- return 0;
- }
- static const neon_xml_elm_t error_elements[] =
- {
- { "DAV:", "error", ELEM_error, 0 },
- {
- "http://apache.org/dav/xmlns", "human-readable",
- ELEM_human_readable, NEON_XML_CDATA
- },
- // our validator doesn't yet recognize the rich, specific
- // <D:some-condition-failed/> objects as defined by DeltaV.
- { NULL }
- };
- static error_t
- xml_parser_cleanup(void * baton)
- {
- ne_xml_destroy(static_cast<ne_xml_parser *>(baton));
- return WEBDAV_NO_ERROR;
- }
- static ne_xml_parser *
- xml_parser_create(
- neon_request_t * req)
- {
- ne_xml_parser * p = ne_xml_create();
- // HACK: Set the parser's error to the empty string. Someday we
- // hope neon will let us have an easy way to tell the difference
- // between XML parsing errors, and errors that occur while handling
- // the XML tags that we get. Until then, trust that whenever neon
- // has an error somewhere below the API, it sets its own error to
- // something non-empty (the API promises non-NULL, at least).
- ne_xml_set_error(p, "");
- apr_pool_cleanup_register(req->pool, p,
- xml_parser_cleanup,
- apr_pool_cleanup_null);
- return p;
- }
- static int
- validate_error_elements(
- neon_xml_elmid parent,
- neon_xml_elmid child)
- {
- switch (parent)
- {
- case ELEM_root:
- if (child == ELEM_error)
- return child;
- else
- return NEON_XML_INVALID;
- case ELEM_error:
- if ((child == ELEM_error) ||
- (child == ELEM_human_readable))
- return child;
- else
- return NEON_XML_DECLINE; // ignore if something else
- // was in there
- default:
- return NEON_XML_DECLINE;
- }
- // NOTREACHED
- }
- static error_t
- generate_error(
- neon_request_t * req,
- apr_pool_t * pool)
- {
- int errcode = WEBDAV_ERR_DAV_REQUEST_FAILED;
- const char * context =
- apr_psprintf(req->pool, "%s of '%s'", req->method, req->url);
- const char * msg = NULL;
- const char * hostport = NULL;
- // Convert the return codes.
- switch (req->rv)
- {
- case NE_OK:
- switch (req->code)
- {
- case 404:
- return error_create(WEBDAV_ERR_FS_NOT_FOUND, NULL,
- apr_psprintf(pool, "'%s' path not found", req->url));
- case 403:
- return error_create(WEBDAV_ERR_DAV_FORBIDDEN, NULL,
- apr_psprintf(pool, "Access to '%s' forbidden",
- req->url));
- case 301:
- case 302:
- case 307:
- return error_create(WEBDAV_ERR_DAV_RELOCATED, NULL,
- apr_psprintf(pool, (req->code == 301) ?
- "WebDAV resource moved permanently to '%s';"
- " please relocate"
- : "WebDAV resource moved temporarily to '%s';"
- " please relocate",
- neon_request_get_location(req, pool)));
- default:
- return error_create(errcode, NULL,
- apr_psprintf(pool,
- "Server sent unexpected return value (%d %s) "
- "in response to %s request for '%s'", req->code,
- req->code_desc, req->method, req->url));
- }
- case NE_AUTH:
- case NE_PROXYAUTH:
- errcode = WEBDAV_ERR_NOT_AUTHORIZED;
- // neon >= 0.27 gives a descriptive error message after auth
- // failure; expose this since it's a useful diagnostic e.g. for
- // an unsupported challenge scheme, or a local GSSAPI error due
- // to an expired ticket.
- WEBDAV_ERR(utf_cstring_to_utf8(&msg, ne_get_error(req->ne_sess), pool));
- msg = apr_psprintf(pool, "authorization failed: %s", msg);
- break;
- case NE_CONNECT:
- msg = "could not connect to server";
- break;
- case NE_TIMEOUT:
- msg = "timed out waiting for server";
- break;
- default:
- // Get the error string from neon and convert to UTF-8.
- WEBDAV_ERR(utf_cstring_to_utf8(&msg, ne_get_error(req->ne_sess), pool));
- break;
- }
- // The hostname may contain non-ASCII characters, so convert it to UTF-8.
- WEBDAV_ERR(utf_cstring_to_utf8(&hostport,
- ne_get_server_hostport(req->ne_sess), pool));
- // This is a translation nightmare. Make sure to compose full strings
- // and mark those for translation.
- return error_createf(errcode, NULL, "%s: %s (%s://%s)",
- context, msg, ne_get_scheme(req->ne_sess),
- hostport);
- }
- typedef struct error_parser_baton
- {
- stringbuf_t * want_cdata;
- stringbuf_t * cdata;
- error_t * dst_err;
- error_t tmp_err;
- bool * marshalled_error;
- } error_parser_baton_t;
- static int
- start_err_element(
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- const neon_xml_elm_t * elm = neon_lookup_xml_elem(error_elements, nspace, name);
- int acc = elm ? validate_error_elements(parent, elm->id) : NEON_XML_DECLINE;
- error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
- error_t * err = &(b->tmp_err);
- if (acc < 1) // ! > 0
- return acc;
- switch (elm->id)
- {
- case ELEM_error:
- {
- // allocate the error_t. Hopefully the value will be
- // overwritten by the <human-readable> tag, or even someday by
- // a <D:failed-precondition/> tag.
- *err = error_create(APR_EGENERAL, NULL,
- "General svn error from server");
- break;
- }
- case ELEM_human_readable:
- {
- // get the errorcode attribute if present
- const char * errcode_str =
- xml_get_attr_value("errcode", // make constant in
- // some mod_dav header?
- atts);
- if (errcode_str && *err)
- {
- apr_int64_t val;
- error_t err2;
- err2 = cstring_atoi64(&val, errcode_str);
- if (err2)
- {
- error_clear(&err2);
- break;
- }
- }
- break;
- }
- default:
- break;
- }
- switch (elm->id)
- {
- case ELEM_human_readable:
- b->want_cdata = b->cdata;
- stringbuf_setempty(b->want_cdata);
- break;
- default:
- b->want_cdata = NULL;
- break;
- }
- return elm->id;
- }
- static int
- end_err_element(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
- error_t * err = &(b->tmp_err);
- switch (state)
- {
- case ELEM_human_readable:
- {
- if (b->cdata->data && err)
- {
- // On the server dav_error_response_tag() will add a leading
- // and trailing newline if DEBUG_CR is defined in mod_dav.h,
- // so remove any such characters here.
- apr_size_t len;
- const char * cd = b->cdata->data;
- if (*cd == '\n')
- ++cd;
- len = strlen(cd);
- if (len > 0 && cd[len - 1] == '\n')
- --len;
- }
- break;
- }
- case ELEM_error:
- {
- if (b->dst_err)
- error_clear(&b->tmp_err);
- else if (b->tmp_err)
- {
- b->dst_err = &b->tmp_err;
- if (b->marshalled_error)
- *(b->marshalled_error) = TRUE;
- }
- b->tmp_err = NULL;
- break;
- }
- default:
- break;
- }
- return 0;
- }
- static int
- collect_error_cdata(
- void * baton,
- int state,
- const char * cdata,
- size_t len)
- {
- stringbuf_t ** b = static_cast<stringbuf_t **>(baton);
- if (*b)
- stringbuf_appendbytes(*b, cdata, len);
- return 0;
- }
- static apr_status_t
- error_parser_baton_cleanup(
- void * baton)
- {
- error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
- if (b->tmp_err)
- error_clear(&b->tmp_err);
- return APR_SUCCESS;
- }
- static ne_xml_parser *
- error_parser_create(
- neon_request_t * req)
- {
- error_parser_baton_t * b = static_cast<error_parser_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
- ne_xml_parser * error_parser = NULL;
- b->dst_err = &(req->err);
- b->marshalled_error = &(req->marshalled_error);
- b->tmp_err = NULL;
- b->want_cdata = NULL;
- b->cdata = stringbuf_create("", req->pool);
- // attach a standard <D:error> body parser to the request
- error_parser = xml_parser_create(req);
- ne_xml_push_handler(error_parser,
- start_err_element,
- collect_error_cdata,
- end_err_element, b);
- apr_pool_cleanup_register(req->pool, b,
- error_parser_baton_cleanup,
- apr_pool_cleanup_null);
- // Register the "error" accepter and body-reader with the request --
- // the one to use when HTTP status is *not* 2XX
- attach_ne_body_reader(req, ra_neon_error_accepter,
- ne_xml_parse_v, error_parser);
- return error_parser;
- }
- static error_t
- neon_maybe_store_auth_info(
- neon_session_t * ras,
- apr_pool_t * pool)
- {
- // No auth_baton? Never mind.
- if (!ras->callbacks->auth_baton)
- return WEBDAV_NO_ERROR;
- // If we ever got credentials, ask the iter_baton to save them.
- return auth_save_credentials(ras->auth_iterstate, pool);
- }
- // A baton that is used along with a set of Neon ne_startelm_cb,
- // ne_cdata_cb, and ne_endelm_cb callbacks to handle conversion
- // from our style errors to Neon style errors.
- // The underlying callbacks are called, and if errors
- // are returned they are stored in this baton and a Neon level
- // error code is returned to the parser.
- typedef struct parser_wrapper_baton_t
- {
- neon_request_t * req;
- ne_xml_parser * parser;
- void * baton;
- neon_startelm_cb_t startelm_cb;
- neon_cdata_cb_t cdata_cb;
- neon_endelm_cb_t endelm_cb;
- } parser_wrapper_baton_t;
- static int
- wrapper_startelm_cb(
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
- int elem = NEON_XML_DECLINE;
- if (pwb->startelm_cb)
- {
- NEON_REQ_ERR(pwb->req, pwb->startelm_cb(&elem, pwb->baton, parent, nspace,
- name, atts));
- }
- if (elem == NEON_XML_INVALID)
- {
- NEON_REQ_ERR(pwb->req, error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL));
- }
- if (pwb->req->err)
- return NE_XML_ABORT;
- return elem;
- }
- static int
- wrapper_cdata_cb(
- void * baton,
- int state,
- const char * cdata,
- size_t len)
- {
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
- if (pwb->cdata_cb)
- {
- NEON_REQ_ERR(pwb->req, pwb->cdata_cb(pwb->baton, state, cdata, len));
- }
- if (pwb->req->err)
- return NE_XML_ABORT;
- return 0;
- }
- static int
- wrapper_endelm_cb(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
- if (pwb->endelm_cb)
- {
- NEON_REQ_ERR(pwb->req, pwb->endelm_cb(pwb->baton, state, nspace, name));
- }
- if (pwb->req->err)
- return NE_XML_ABORT;
- return 0;
- }
- static error_t
- neon_check_parse_error(
- const char * method,
- ne_xml_parser * xml_parser,
- const char * url)
- {
- const char * msg = ne_xml_get_error(xml_parser);
- if (msg != NULL && *msg != '\0')
- return error_createf(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
- "The %s request returned invalid XML "
- "in the response: %s (%s)",
- method, msg, url);
- return WEBDAV_NO_ERROR;
- }
- static int
- wrapper_reader_cb(
- void * baton,
- const char * data,
- size_t len)
- {
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
- neon_session_t * sess = pwb->req->sess;
- int parser_status = 0;
- if (pwb->req->err)
- return 1;
- if (sess->callbacks->cancel_func)
- {
- NEON_REQ_ERR(pwb->req, (sess->callbacks->cancel_func)(sess->callback_baton));
- }
- if (pwb->req->err)
- return 1;
- if (len)
- parser_status = ne_xml_parse(pwb->parser, data, len);
- if (parser_status)
- {
- // Pass XML parser error.
- NEON_REQ_ERR(pwb->req, neon_check_parse_error(pwb->req->method,
- pwb->parser,
- pwb->req->url));
- }
- return parser_status;
- }
- // Create a Neon xml parser with callbacks STARTELM_CB, ENDELM_CB and
- // CDATA_CB. The created parser wraps the Neon callbacks and marshals any
- // errors returned by the callbacks through the Neon layer. Any errors
- // raised will be returned by neon_request_dispatch() unless
- // an earlier error occurred.
- // Register a pool cleanup on the pool of REQ to clean up any allocated
- // Neon resources.
- // Return the new parser. Also attach it to REQ if ACCPT is non-null.
- // ACCPT indicates whether the parser wants to read the response body
- // or not. Pass NULL for ACCPT when you don't want the returned parser
- // to be attached to REQ.
- static ne_xml_parser *
- neon_xml_parser_create(
- neon_request_t * req,
- ne_accept_response accpt,
- neon_startelm_cb_t startelm_cb,
- neon_cdata_cb_t cdata_cb,
- neon_endelm_cb_t endelm_cb,
- void * baton)
- {
- ne_xml_parser * p = xml_parser_create(req);
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(apr_pcalloc(req->pool, sizeof(*pwb)));
- pwb->req = req;
- pwb->parser = p;
- pwb->baton = baton;
- pwb->startelm_cb = startelm_cb;
- pwb->cdata_cb = cdata_cb;
- pwb->endelm_cb = endelm_cb;
- ne_xml_push_handler(p,
- wrapper_startelm_cb,
- wrapper_cdata_cb,
- wrapper_endelm_cb, pwb);
- if (accpt)
- attach_ne_body_reader(req, accpt, wrapper_reader_cb, pwb);
- return p;
- }
- static error_t
- neon_request_dispatch(
- int * code_p,
- neon_request_t * req,
- apr_hash_t * extra_headers,
- const char * body,
- int okay_1,
- int okay_2,
- bool check_errors,
- apr_pool_t * pool)
- {
- // add any extra headers passed in by caller.
- if (extra_headers != NULL)
- {
- for (apr_hash_index_t * hi = apr_hash_first(pool, extra_headers); hi;
- hi = apr_hash_next(hi))
- {
- const void * key;
- void * val;
- apr_hash_this(hi, &key, NULL, &val);
- ne_add_request_header(req->ne_req,
- static_cast<const char *>(key), static_cast<const char *>(val));
- }
- }
- if (body)
- ne_set_request_body_buffer(req->ne_req, body, strlen(body));
- // attach a standard <D:error> body parser to the request
- ne_xml_parser * error_parser = error_parser_create(req);
- if (check_errors)
- multistatus_parser_create(req);
- // run the request, see what comes back.
- req->rv = ne_request_dispatch(req->ne_req);
- // Save values from the request
- const ne_status * statstruct = ne_get_status(req->ne_req);
- req->code_desc = apr_pstrdup(pool, statstruct->reason_phrase);
- req->code = statstruct->code;
- // If we see a successful request that used authentication, we should store
- // the credentials for future use.
- if ((req->sess->auth_used) && (statstruct->code < 400))
- {
- req->sess->auth_used = FALSE;
- WEBDAV_ERR(neon_maybe_store_auth_info(req->sess, pool));
- }
- if (code_p)
- *code_p = req->code;
- if (!req->marshalled_error && req->err)
- WEBDAV_ERR(req->err);
- // If the status code was one of the two that we expected, then go
- // ahead and return now. IGNORE any marshalled error.
- if ((req->rv == NE_OK) && (req->code == okay_1 || req->code == okay_2))
- return WEBDAV_NO_ERROR;
- // Any other errors? Report them
- if (req->err)
- WEBDAV_ERR(req->err);
- WEBDAV_ERR(neon_check_parse_error(req->method, error_parser, req->url));
- // We either have a neon error, or some other error
- // that we didn't expect.
- return generate_error(req, pool);
- }
- static const char *
- neon_request_get_location(
- neon_request_t * request,
- apr_pool_t * pool)
- {
- const char * val = ne_get_response_header(request->ne_req, "Location");
- return val ? urlpath_canonicalize(val, pool) : NULL;
- }
- static error_t
- neon_request_create(
- neon_request_t ** request,
- neon_session_t * sess,
- const char * method, const char * url,
- apr_pool_t * pool)
- {
- apr_pool_t * reqpool = webdav_pool_create(pool);
- neon_request_t * req = NULL;
- const char * path = NULL;
- // We never want to send Neon an absolute URL, since that can cause
- // problems with some servers (for example, those that may be accessed
- // using different server names from different locations, or those that
- // want to rewrite the incoming URL). If the URL passed in is absolute,
- // convert it to a path-absolute relative URL.
- path = path_from_url(url);
- req = static_cast<neon_request_t *>(apr_pcalloc(reqpool, sizeof(*req)));
- req->ne_sess = sess->ne_sess;
- req->ne_req = ne_request_create(req->ne_sess, method, path);
- req->sess = sess;
- req->pool = reqpool;
- req->iterpool = webdav_pool_create(req->pool);
- req->method = apr_pstrdup(req->pool, method);
- req->url = apr_pstrdup(req->pool, url);
- req->rv = -1;
- // Neon resources may be NULL on out-of-memory
- assert(req->ne_req != NULL);
- apr_pool_cleanup_register(sess->pool, req,
- dav_request_sess_cleanup,
- apr_pool_cleanup_null);
- apr_pool_cleanup_register(reqpool, req,
- dav_request_cleanup,
- apr_pool_cleanup_null);
- *request = req;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- get_path_relative_to_session(
- session_t * session,
- const char ** rel_path,
- const char * url,
- apr_pool_t * pool)
- {
- const char * sess_url = NULL;
- WEBDAV_ERR(session->vtable->get_session_url(session, &sess_url, pool));
- if (strcmp(sess_url, url) == 0)
- {
- *rel_path = "";
- }
- else
- {
- *rel_path = uri_is_child(sess_url, url, pool);
- if (!*rel_path)
- {
- return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "'%s' isn't a child of session URL '%s'", url, sess_url);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_path_relative_to_root(
- const char ** rel_path,
- const char * abspath_or_url,
- const char * webdav_root,
- bool include_leading_slash,
- session_t * ra_session,
- apr_pool_t * result_pool,
- apr_pool_t * scratch_pool)
- {
- const char * webdav_relpath = NULL;
- if (!path_is_url(abspath_or_url))
- {
- error_createf(WEBDAV_ERR_DAV_NOT_IMPLEMENTED, NULL,
- "not implemented: 'client_path_relative_to_root'");
- }
- // Merge handling passes a root that is not WebDAV resource root
- else if (webdav_root != NULL)
- {
- /*if (!uri_is_ancestor(webdav_root, abspath_or_url))
- return error_createf(WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
- "URL '%s' is not a child of "
- "root URL '%s'",
- abspath_or_url, webdav_root);*/
- webdav_relpath = uri_skip_ancestor(webdav_root, abspath_or_url,
- result_pool);
- }
- else
- {
- error_t err = 0;
- WEBDAV_ERR_ASSERT(ra_session != NULL);
- // Ask the RA layer to create a relative path for us
- err = get_path_relative_to_root(ra_session, &webdav_relpath,
- abspath_or_url, scratch_pool);
- if (err)
- {
- if (err == WEBDAV_ERR_ILLEGAL_URL)
- {
- return error_createf(WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES, &err,
- "URL '%s' is not inside WebDAV resource root", abspath_or_url);
- }
- return error_trace(err);
- }
- }
- if (include_leading_slash)
- *rel_path = apr_pstrcat(result_pool, "/", webdav_relpath, NULL);
- else
- *rel_path = webdav_relpath;
- return WEBDAV_NO_ERROR;
- }
- static const char *
- neon_uri_unparse(
- const ne_uri * uri,
- apr_pool_t * pool)
- {
- char * unparsed_uri = NULL;
- const char * result = NULL;
- // Unparse uri.
- unparsed_uri = ne_uri_unparse(uri);
- result = uri_canonicalize(unparsed_uri, pool);
- // Free neon's allocated copy.
- ne_free(unparsed_uri);
- // Return string allocated in result pool.
- return result;
- }
- typedef struct body_reader_wrapper_baton_t
- {
- neon_request_t * req;
- neon_block_reader real_reader;
- void * real_baton;
- } body_reader_wrapper_baton_t;
- static int
- body_reader_wrapper(
- void * userdata,
- const char * data,
- size_t len)
- {
- body_reader_wrapper_baton_t * b = static_cast<body_reader_wrapper_baton_t *>(userdata);
- if (b->req->err)
- // We already had an error? Bail out.
- return 1;
- NEON_REQ_ERR(b->req, b->real_reader(b->real_baton, data, len));
- if (b->req->err)
- return 1;
- return 0;
- }
- static void
- neon_add_response_body_reader(
- neon_request_t * req,
- ne_accept_response accpt,
- neon_block_reader reader,
- void * userdata)
- {
- body_reader_wrapper_baton_t * b = static_cast<body_reader_wrapper_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
- b->req = req;
- b->real_baton = userdata;
- b->real_reader = reader;
- attach_ne_body_reader(req, accpt, body_reader_wrapper, b);
- }
- //------------------------------------------------------------------------------
- // from fetch.c
- typedef struct file_read_ctx_t
- {
- apr_pool_t * pool;
- // these two are the handler that the editor gave us
- void * handler_baton;
- // if we're receiving an svndiff, this is a parser which places the
- // resulting windows into the above handler/baton.
- stream_t * stream;
- } file_read_ctx_t;
- typedef struct file_write_ctx_t
- {
- stream_t * stream; // stream to write file contents to
- } file_write_ctx_t;
- typedef struct custom_get_ctx_t
- {
- neon_request_t * req; // Used to propagate errors out of the reader
- int checked_type; // have we processed ctype yet?
- void * subctx;
- void * callback_baton;
- } custom_get_ctx_t;
- // Helper for neon_get_file. This implements
- // the neon_block_reader() callback interface.
- static error_t
- get_file_reader(
- void * userdata,
- const char * buf,
- size_t len)
- {
- custom_get_ctx_t * cgc = static_cast<custom_get_ctx_t *>(userdata);
- if (cgc->req->sess->callbacks &&
- cgc->req->sess->callbacks->cancel_func)
- {
- NEON_REQ_ERR(cgc->req, (cgc->req->sess->callbacks->cancel_func)(
- cgc->req->sess->callback_baton));
- }
- assert(cgc->callback_baton);
- callback_baton_t * cb = static_cast<callback_baton_t *>(cgc->callback_baton);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- fs->AdjustToCPSLimit(len);
- // The stream we want to push data at.
- file_write_ctx_t * fwc = static_cast<file_write_ctx_t *>(cgc->subctx);
- stream_t * stream = fwc->stream;
- // Write however many bytes were passed in by neon.
- WEBDAV_ERR(stream_write(stream, buf, &len));
- return WEBDAV_NO_ERROR;
- }
- static error_t
- custom_get_request(
- neon_session_t * ras,
- const char * url,
- const char * editor_relpath,
- neon_block_reader reader,
- void * subctx,
- void * cb_baton,
- apr_pool_t * pool)
- {
- custom_get_ctx_t cgc = { 0 };
- neon_request_t * request = NULL;
- error_t err = 0;
- WEBDAV_ERR(neon_request_create(&request, ras, "GET", url, pool));
- neon_add_response_body_reader(request, ne_accept_2xx, reader, &cgc);
- // complete initialization of the body reading context
- cgc.req = request;
- cgc.subctx = subctx;
- cgc.callback_baton = cb_baton;
- // run the request
- err = neon_request_dispatch(NULL, request, NULL, NULL,
- 200 /* OK */,
- 226 /* IM Used */,
- false,
- pool);
- neon_request_destroy(request);
- // The request runner raises internal errors before Neon errors,
- // pass a returned error to our callers
- return err;
- }
- //------------------------------------------------------------------------------
- static error_t
- get_file(
- session_t * session,
- const char * path,
- stream_t * stream,
- apr_hash_t ** props,
- apr_pool_t * pool)
- {
- WEBDAV_ERR_ASSERT(*path != '/');
- return session->vtable->get_file(session, path,
- stream,
- props, pool);
- }
- static error_t
- get_dir2(
- session_t * session,
- apr_hash_t ** dirents,
- const char * path,
- apr_uint32_t dirent_fields,
- apr_pool_t * pool)
- {
- WEBDAV_ERR_ASSERT(*path != '/');
- return session->vtable->get_dir(session, dirents,
- path,
- dirent_fields, pool);
- }
- static error_t
- get_webdav_resource_root2(
- session_t * session,
- const char ** url,
- apr_pool_t * pool)
- {
- WEBDAV_ERR(session->vtable->get_webdav_resource_root(session, url, pool));
- *url = *url ? apr_pstrdup(pool, *url) : NULL;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- stat(
- session_t * session,
- const char * path,
- dirent_t ** dirent,
- apr_pool_t * pool)
- {
- WEBDAV_ERR_ASSERT(*path != '/');
- return session->vtable->stat(session, path,
- dirent, pool);
- }
- static error_t
- get_path_relative_to_root(
- session_t * session,
- const char ** rel_path,
- const char * url,
- apr_pool_t * pool)
- {
- const char * root_url = NULL;
- WEBDAV_ERR(session->vtable->get_webdav_resource_root(session, &root_url, pool));
- if (strcmp(root_url, url) == 0)
- {
- *rel_path = "";
- }
- else
- {
- *rel_path = uri_is_child(root_url, url, pool);
- if (!*rel_path)
- {
- return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "'%s' isn't a child of root URL '%s'", url, root_url);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- check_path(
- session_t * session,
- const char * path,
- node_kind_t * kind,
- apr_pool_t * pool)
- {
- WEBDAV_ERR_ASSERT(*path != '/');
- return session->vtable->check_path(session, path,
- kind, pool);
- }
- static error_t
- reparent(
- session_t * session,
- const char * url,
- apr_pool_t * pool)
- {
- return session->vtable->reparent(session, url, pool);
- }
- static error_t
- session_open(
- session_t ** session_p,
- const char ** corrected_url_p,
- const char * session_URL,
- const callbacks2_t * callbacks,
- void * callback_baton,
- apr_pool_t * pool)
- {
- assert(callback_baton);
- // check options, url, prepare parameters, callbacks, auth etc
- apr_pool_t * sesspool = webdav_pool_create(pool);
- // Initialize the return variable.
- *session_p = NULL;
- ne_uri * webdav_URI = NULL;
- error_t err = parse_ne_uri(&webdav_URI, session_URL, sesspool);
- if ((err != WEBDAV_NO_ERROR) || (webdav_URI->host == NULL))
- {
- return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "Illegal URL '%s'", session_URL);
- }
- // Auth caching parameters.
- bool store_passwords = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
- bool store_auth_creds = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
- const char * store_plaintext_passwords = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
- bool store_pp = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
- const char * store_pp_plaintext = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
- if (callbacks->auth_baton)
- {
- if (auth_baton_get_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
- {
- store_passwords = FALSE;
- }
- if (auth_baton_get_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
- {
- store_auth_creds = FALSE;
- }
- }
- if (callbacks->auth_baton)
- {
- // Save auth caching parameters in the auth parameter hash.
- if (!store_passwords)
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
- store_plaintext_passwords);
- if (!store_pp)
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
- "");
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
- store_pp_plaintext);
- if (!store_auth_creds)
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE, "");
- }
- const vtable_t * vtable = NULL;
- WEBDAV_ERR(neon_init(&vtable, sesspool));
- // Create the session object.
- session_t * session = static_cast<session_t *>(apr_pcalloc(sesspool, sizeof(*session)));
- session->vtable = vtable;
- session->pool = sesspool;
- const char * corrected_url = NULL;
- // Ask the library to open the session.
- WEBDAV_ERR_W(vtable->open_session(
- session,
- &corrected_url,
- session_URL,
- callbacks, callback_baton, sesspool),
- apr_psprintf(pool, "Unable to connect to a WebDAV resource at URL '%s'",
- session_URL));
- if (corrected_url_p && corrected_url)
- {
- if (!path_is_url(corrected_url))
- {
- ne_uri * corrected_URI = NULL;
- WEBDAV_ERR(parse_ne_uri(&corrected_URI, session_URL, sesspool));
- if (corrected_URI->path) ne_free(corrected_URI->path);
- corrected_URI->path = ne_strdup(corrected_url);
- corrected_url = neon_uri_unparse(corrected_URI, pool);
- }
- *corrected_url_p = uri_canonicalize(corrected_url, pool);
- webdav_pool_destroy(sesspool);
- return WEBDAV_NO_ERROR;
- }
- *session_p = session;
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // This implements the client_list_func_t API
- static error_t
- list_func(
- void * baton,
- const char * path,
- const dirent_t * dirent,
- const char * abs_path,
- apr_pool_t * pool)
- {
- list_func_baton_t * pb = static_cast<list_func_baton_t *>(baton);
- assert(pb);
- assert(pb->entries);
- const char * entryname = NULL;
- neon_session_t * ras = static_cast<neon_session_t *>(pb->session->priv);
- assert(ras);
- if (ras->callbacks->cancel_func)
- WEBDAV_ERR(ras->callbacks->cancel_func(ras->callback_baton));
- if (strcmp(path, "") == 0)
- {
- if (dirent->kind == node_file)
- entryname = dirent_basename(abs_path, pool);
- else if (pb->verbose)
- entryname = ".";
- else
- // Don't bother to list if no useful information will be shown.
- return WEBDAV_NO_ERROR;
- }
- else
- entryname = path;
- if (pb->verbose)
- {
- apr_time_t now = apr_time_now();
- apr_time_exp_t exp_time;
- apr_status_t apr_err;
- apr_size_t size;
- char timestr[20];
- const char * utf8_timestr;
- // time_to_human_cstring gives us something *way* too long
- // to use for this, so we have to roll our own. We include
- // the year if the entry's time is not within half a year.
- apr_time_exp_lt(&exp_time, dirent->time);
- if (apr_time_sec(now - dirent->time) < (365 * 86400 / 2) &&
- apr_time_sec(dirent->time - now) < (365 * 86400 / 2))
- {
- apr_err = apr_strftime(timestr, &size, sizeof(timestr),
- "%b %d %H:%M", &exp_time);
- }
- else
- {
- apr_err = apr_strftime(timestr, &size, sizeof(timestr),
- "%b %d %Y", &exp_time);
- }
- // if that failed, just zero out the string and print nothing
- if (apr_err)
- timestr[0] = '\0';
- // we need it in UTF-8.
- WEBDAV_ERR(utf_cstring_to_utf8(&utf8_timestr, timestr, pool));
- TListDataEntry entry = {NULL, NULL, NULL, 0, false, false, {0}, NULL};
- if (APR_SUCCESS != utf8_to_unicode(const_cast<wchar_t **>(&entry.Name), entryname, pb->pool))
- {
- return error_create(WEBDAV_ERR_DAV_MALFORMED_DATA, NULL, NULL);
- }
- entry.Permissions = L"";
- entry.OwnerGroup = L"";
- int dir = dirent->kind == node_dir;
- entry.Size = dir == 0 ? dirent->size : 0;
- entry.Dir = dir != 0;
- entry.Link = false;
- entry.Time.Year = exp_time.tm_year + 1900;
- entry.Time.Month = exp_time.tm_mon + 1;
- entry.Time.Day = exp_time.tm_mday;
- entry.Time.Hour = exp_time.tm_hour;
- entry.Time.Minute = exp_time.tm_min;
- entry.Time.Second = exp_time.tm_sec;
- entry.Time.HasTime = true;
- entry.Time.HasSeconds = true;
- entry.Time.HasDate = true;
- entry.LinkTarget = L"";
- pb->entries->push_back(entry);
- }
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from url.c
- static error_t
- client_url_from_path2(
- const char ** url,
- const char * path_or_url,
- stringbuf_t * session_url,
- apr_pool_t * result_pool,
- apr_pool_t * scratch_pool)
- {
- if (!path_is_url(path_or_url))
- {
- ne_uri * uri = NULL;
- WEBDAV_ERR(parse_ne_uri(&uri, session_url->data, result_pool));
- if (uri->path) ne_free(uri->path);
- uri->path = ne_strdup(path_or_url);
- const char * corrected_url = neon_uri_unparse(uri, result_pool);
- *url = uri_canonicalize(corrected_url, result_pool);
- }
- else
- *url = uri_canonicalize(path_or_url, result_pool);
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from ctx.c
- static error_t
- client_create_context(
- client_ctx_t ** ctx,
- apr_pool_t * pool)
- {
- *ctx = static_cast<client_ctx_t *>(apr_pcalloc(pool, sizeof(client_ctx_t)));
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from auth.c
- static void
- auth_baton_create(
- auth_baton_t ** auth_baton,
- apr_pool_t * pool)
- {
- auth_baton_t * ab = NULL;
- // Build the auth_baton.
- ab = static_cast<auth_baton_t *>(apr_pcalloc(pool, sizeof(*ab)));
- ab->tables = apr_hash_make(pool);
- ab->parameters = apr_hash_make(pool);
- ab->creds_cache = apr_hash_make(pool);
- ab->pool = pool;
- *auth_baton = ab;
- }
- static void
- create_baton_open(
- auth_baton_t * auth_baton,
- const apr_array_header_t * providers,
- apr_pool_t * pool)
- {
- auth_provider_object_t * provider = NULL;
- // Register each provider in order. Providers of different
- // credentials will be automatically sorted into different tables by
- // register_provider().
- if (providers)
- {
- for (int i = 0; i < providers->nelts; i++)
- {
- provider_set_t * table = NULL;
- provider = APR_ARRAY_IDX(providers, i, auth_provider_object_t *);
- // Add it to the appropriate table in the auth_baton
- table = static_cast<provider_set_t *>(apr_hash_get(auth_baton->tables,
- provider->vtable->cred_kind, APR_HASH_KEY_STRING));
- if (!table)
- {
- table = static_cast<provider_set_t *>(apr_pcalloc(pool, sizeof(*table)));
- table->providers = apr_array_make(pool, 1, sizeof(auth_provider_object_t *));
- apr_hash_set(auth_baton->tables,
- provider->vtable->cred_kind, APR_HASH_KEY_STRING,
- table);
- }
- APR_ARRAY_PUSH(table->providers, auth_provider_object_t *) = provider;
- }
- }
- }
- //---------------------------------------------------------------------------
- // from ssl_client_cert_providers.c
- // A function returning an SSL client certificate passphrase provider.
- typedef void (*auth_ssl_client_cert_pw_provider_func_t)(
- auth_provider_object_t ** provider,
- apr_pool_t * pool);
- // retrieve and load the ssl client certificate file from servers config
- static error_t
- ssl_client_cert_file_first_credentials(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- const char * cert_file;
- cert_file = NULL;
- if (cert_file != NULL)
- {
- auth_cred_ssl_client_cert_t * cred =
- static_cast<auth_cred_ssl_client_cert_t *>(apr_pcalloc(pool, sizeof(*cred)));
- cred->cert_file = cert_file;
- cred->may_save = FALSE;
- *credentials_p = cred;
- }
- else
- {
- *credentials_p = NULL;
- }
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t ssl_client_cert_file_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT,
- ssl_client_cert_file_first_credentials,
- NULL,
- NULL
- };
- // Public API to SSL file providers.
- static void
- auth_get_ssl_client_cert_file_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &ssl_client_cert_file_provider;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Prompt provider
- /*-----------------------------------------------------------------------*/
- // Baton type for prompting to send client ssl creds.
- // There is no iteration baton type.
- typedef struct ssl_client_cert_prompt_provider_baton_t
- {
- auth_ssl_client_cert_prompt_func_t prompt_func;
- void * prompt_baton;
- // how many times to re-prompt after the first one fails
- int retry_limit;
- } ssl_client_cert_prompt_provider_baton_t;
- // Iteration baton.
- typedef struct ssl_client_cert_prompt_iter_baton_t
- {
- // The original provider baton
- ssl_client_cert_prompt_provider_baton_t * pb;
- // The original realmstring
- const char * realmstring;
- // how many times we've reprompted
- int retries;
- } ssl_client_cert_prompt_iter_baton_t;
- static error_t
- ssl_client_cert_prompt_first_cred(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_client_cert_prompt_provider_baton_t * pb =
- static_cast<ssl_client_cert_prompt_provider_baton_t *>(provider_baton);
- ssl_client_cert_prompt_iter_baton_t * ib =
- static_cast<ssl_client_cert_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ib)));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_client_cert_t **) credentials_p,
- pb->prompt_baton, realmstring, !no_auth_cache,
- pool));
- ib->pb = pb;
- ib->realmstring = apr_pstrdup(pool, realmstring);
- ib->retries = 0;
- *iter_baton = ib;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- ssl_client_cert_prompt_next_cred(
- void ** credentials_p,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_client_cert_prompt_iter_baton_t * ib =
- static_cast<ssl_client_cert_prompt_iter_baton_t *>(iter_baton);
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if ((ib->pb->retry_limit >= 0) && (ib->retries >= ib->pb->retry_limit))
- {
- // give up, go on to next provider.
- *credentials_p = NULL;
- return WEBDAV_NO_ERROR;
- }
- ib->retries++;
- return ib->pb->prompt_func((auth_cred_ssl_client_cert_t **)
- credentials_p, ib->pb->prompt_baton,
- ib->realmstring, !no_auth_cache, pool);
- }
- static const auth_provider_t ssl_client_cert_prompt_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT,
- ssl_client_cert_prompt_first_cred,
- ssl_client_cert_prompt_next_cred,
- NULL
- };
- // Public API to SSL prompting providers.
- static void
- auth_get_ssl_client_cert_prompt_provider(
- auth_provider_object_t ** provider,
- auth_ssl_client_cert_prompt_func_t prompt_func,
- void * prompt_baton,
- int retry_limit,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- ssl_client_cert_prompt_provider_baton_t * pb =
- static_cast<ssl_client_cert_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->retry_limit = retry_limit;
- po->vtable = &ssl_client_cert_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //---------------------------------------------------------------------------
- // from ssl_server_trust_providers.c
- // retrieve ssl server CA failure overrides (if any) from servers config
- static error_t
- ssl_server_trust_file_first_credentials(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_FAILURES,
- APR_HASH_KEY_STRING));
- const auth_ssl_server_cert_info_t * cert_info =
- static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- APR_HASH_KEY_STRING));
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- apr_hash_t * creds_hash = NULL;
- error_t error = WEBDAV_NO_ERROR;
- *credentials = NULL;
- *iter_baton = NULL;
- // Check if this is a permanently accepted certificate
- error = config_read_auth_data(&creds_hash, AUTH_CRED_SSL_SERVER_TRUST,
- realmstring, fs, pool);
- error_clear(&error);
- if (!error && creds_hash)
- {
- string_t * trusted_cert, *this_cert, *failstr;
- apr_uint32_t last_failures = 0;
- trusted_cert = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_ASCII_CERT_KEY,
- APR_HASH_KEY_STRING));
- this_cert = string_create(cert_info->fingerprint, pool);
- failstr = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_FAILURES_KEY,
- APR_HASH_KEY_STRING));
- if (failstr)
- {
- char * endptr;
- unsigned long tmp_ulong = strtoul(failstr->data, &endptr, 10);
- if (*endptr == '\0')
- last_failures = (apr_uint32_t) tmp_ulong;
- }
- // If the cert is trusted and there are no new failures, we
- // accept it by clearing all failures.
- if (trusted_cert &&
- string_compare(this_cert, trusted_cert) &&
- (*failures & ~last_failures) == 0)
- {
- *failures = 0;
- }
- }
- // If all failures are cleared now, we return the creds
- if (!*failures)
- {
- auth_cred_ssl_server_trust_t * creds =
- static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(*creds)));
- creds->may_save = FALSE; // No need to save it again...
- *credentials = creds;
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- ssl_server_trust_file_save_credentials(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- auth_cred_ssl_server_trust_t * creds =
- static_cast<auth_cred_ssl_server_trust_t *>(credentials);
- const auth_ssl_server_cert_info_t * cert_info;
- apr_hash_t * creds_hash = NULL;
- if (!creds->may_save)
- return WEBDAV_NO_ERROR;
- cert_info = static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- APR_HASH_KEY_STRING));
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- creds_hash = apr_hash_make(pool);
- apr_hash_set(creds_hash, AUTHN_ASCII_CERT_KEY, APR_HASH_KEY_STRING,
- string_create(cert_info->fingerprint, pool));
- apr_hash_set(creds_hash, AUTHN_FAILURES_KEY, APR_HASH_KEY_STRING,
- string_createf(pool, "%lu", (unsigned long)
- creds->accepted_failures));
- WEBDAV_ERR(config_write_auth_data(creds_hash,
- AUTH_CRED_SSL_SERVER_TRUST,
- realmstring,
- fs,
- pool));
- *saved = TRUE;
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t ssl_server_trust_file_provider =
- {
- AUTH_CRED_SSL_SERVER_TRUST,
- &ssl_server_trust_file_first_credentials,
- NULL,
- &ssl_server_trust_file_save_credentials,
- };
- // Public API to SSL file providers.
- static void
- auth_get_ssl_server_trust_file_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &ssl_server_trust_file_provider;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Prompt provider
- /*-----------------------------------------------------------------------*/
- // Baton type for prompting to verify server ssl creds.
- // There is no iteration baton type.
- typedef struct ssl_server_trust_prompt_provider_baton_t
- {
- auth_ssl_server_trust_prompt_func_t prompt_func;
- void * prompt_baton;
- } ssl_server_trust_prompt_provider_baton_t;
- static error_t
- ssl_server_trust_prompt_first_cred(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_server_trust_prompt_provider_baton_t * pb =
- static_cast<ssl_server_trust_prompt_provider_baton_t *>(provider_baton);
- apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_FAILURES,
- APR_HASH_KEY_STRING));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- const auth_ssl_server_cert_info_t * cert_info =
- static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_server_trust_t **)
- credentials_p, pb->prompt_baton, realmstring,
- *failures, cert_info, !no_auth_cache &&
- !(*failures & WEBDAV_AUTH_SSL_OTHER), pool));
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t ssl_server_trust_prompt_provider =
- {
- AUTH_CRED_SSL_SERVER_TRUST,
- ssl_server_trust_prompt_first_cred,
- NULL,
- NULL
- };
- // Public API to SSL prompting providers.
- static void
- auth_get_ssl_server_trust_prompt_provider(
- auth_provider_object_t ** provider,
- auth_ssl_server_trust_prompt_func_t prompt_func,
- void * prompt_baton,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- ssl_server_trust_prompt_provider_baton_t * pb =
- static_cast<ssl_server_trust_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- po->vtable = &ssl_server_trust_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //---------------------------------------------------------------------------
- // from cmdline.h
- typedef struct cmdline_prompt_baton2_t
- {
- cancel_func_t cancel_func;
- void * cancel_baton;
- } cmdline_prompt_baton2_t;
- //---------------------------------------------------------------------------
- // from prompt.c
- // This is a helper for plaintext prompt functions.
- static error_t
- plaintext_prompt_helper(
- bool * may_save_plaintext,
- const char * realmstring,
- const char * prompt_string,
- const char * prompt_text,
- void * baton,
- apr_pool_t * pool)
- {
- cmdline_prompt_baton2_t * pb = static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- error_t err = fs->SimplePrompt(prompt_text, prompt_string, RequestResult);
- if (err)
- {
- if (err == WEBDAV_ERR_CANCELLED)
- {
- error_clear(&err);
- *may_save_plaintext = FALSE;
- return WEBDAV_NO_ERROR;
- }
- else
- return err;
- }
- if (RequestResult == qaYes)
- {
- *may_save_plaintext = TRUE;
- }
- else if (RequestResult == qaNo)
- {
- *may_save_plaintext = FALSE;
- }
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_plaintext_prompt_func_t'.
- static error_t
- cmdline_auth_plaintext_prompt(
- bool * may_save_plaintext,
- const char * realmstring,
- void * baton,
- apr_pool_t * pool)
- {
- const char * prompt_string = "Store password unencrypted (yes/no)? ";
- const char * prompt_text =
- "\n-----------------------------------------------------------------------"
- "\nATTENTION! Your password for authentication realm:\n"
- "\n"
- " %s\n"
- "\n"
- "can only be stored to disk unencrypted! You are advised to configure\n"
- "your system so that system can store passwords encrypted, if\n"
- "possible. See the documentation for details.\n"
- "\n"
- "You can avoid future appearances of this warning by setting the value\n"
- "of the 'store-plaintext-passwords' option to either 'yes' or 'no' in\n"
- "'%s'.\n"
- "-----------------------------------------------------------------------\n"
- ;
- return plaintext_prompt_helper(may_save_plaintext, realmstring,
- prompt_string, prompt_text, baton,
- pool);
- }
- // This implements 'auth_plaintext_passphrase_prompt_func_t'.
- static error_t
- cmdline_auth_plaintext_passphrase_prompt(
- bool * may_save_plaintext,
- const char * realmstring,
- void * baton,
- apr_pool_t * pool)
- {
- const char * prompt_string = "Store passphrase unencrypted (yes/no)? ";
- const char * prompt_text =
- "\n-----------------------------------------------------------------------\n"
- "ATTENTION! Your passphrase for client certificate:\n"
- "\n"
- " %s\n"
- "\n"
- "can only be stored to disk unencrypted! You are advised to configure\n"
- "your system so that system can store passphrase encrypted, if\n"
- "possible. See the documentation for details.\n"
- "\n"
- "You can avoid future appearances of this warning by setting the value\n"
- "of the 'store-ssl-client-cert-pp-plaintext' option to either 'yes' or\n"
- "'no' in '%s'.\n"
- "-----------------------------------------------------------------------\n"
- ;
- return plaintext_prompt_helper(may_save_plaintext, realmstring,
- prompt_string, prompt_text, baton,
- pool);
- }
- // This implements 'auth_ssl_server_trust_prompt_func_t'.
- static error_t
- cmdline_auth_ssl_server_trust_prompt(
- auth_cred_ssl_server_trust_t ** cred_p,
- void * baton,
- const char * realm,
- apr_uint32_t failures,
- const auth_ssl_server_cert_info_t * cert_info,
- bool may_save,
- apr_pool_t * pool)
- {
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- stringbuf_t * buf = stringbuf_create("", pool);
- /*if (failures & WEBDAV_AUTH_SSL_UNKNOWNCA)
- {
- stringbuf_appendcstr(buf,
- " - The certificate is not issued by a trusted authority. Use the\n"
- " fingerprint to validate the certificate manually!\n");
- }*/
- if (failures & WEBDAV_AUTH_SSL_CNMISMATCH)
- {
- stringbuf_appendcstr(buf, "- The certificate hostname does not match.\n");
- }
- if (failures & WEBDAV_AUTH_SSL_NOTYETVALID)
- {
- stringbuf_appendcstr(buf, "- The certificate is not yet valid.\n");
- }
- if (failures & WEBDAV_AUTH_SSL_EXPIRED)
- {
- stringbuf_appendcstr(buf, "- The certificate has expired.\n");
- }
- if (failures & WEBDAV_AUTH_SSL_OTHER)
- {
- stringbuf_appendcstr(buf, "- The certificate has an unknown error.\n");
- }
- stringbuf_t * msg = stringbuf_createf(pool,
- // "Certificate information:\n"
- " - Hostname: %s\n"
- " - Valid: from %s until %s\n"
- " - Issuer: %s\n"
- " - Fingerprint: %s",
- cert_info->hostname,
- cert_info->valid_from,
- cert_info->valid_until,
- cert_info->issuer_dname,
- cert_info->fingerprint);
- stringbuf_appendstr(buf, msg);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- WEBDAV_ERR(fs->VerifyCertificate(buf->data, cert_info->fingerprint, RequestResult));
- if (RequestResult == qaYes)
- {
- *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->may_save = TRUE;
- (*cred_p)->accepted_failures = failures;
- }
- else if (RequestResult == qaNo)
- {
- *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->may_save = FALSE;
- (*cred_p)->accepted_failures = failures;
- }
- else
- {
- *cred_p = NULL;
- }
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_ssl_client_cert_prompt_func_t'.
- static error_t
- cmdline_auth_ssl_client_cert_prompt(
- auth_cred_ssl_client_cert_t ** cred_p,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool)
- {
- auth_cred_ssl_client_cert_t * cred = NULL;
- const char * cert_file = NULL;
- const char * abs_cert_file = NULL;
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- WEBDAV_ERR(fs->AskForClientCertificateFilename(&cert_file, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- WEBDAV_ERR(dirent_get_absolute(&abs_cert_file, cert_file, pool));
- cred = static_cast<auth_cred_ssl_client_cert_t *>(apr_pcalloc(pool, sizeof(*cred)));
- cred->cert_file = abs_cert_file;
- cred->may_save = may_save;
- *cred_p = cred;
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_ssl_client_cert_pw_prompt_func_t'.
- static error_t
- cmdline_auth_ssl_client_cert_pw_prompt(
- auth_cred_ssl_client_cert_pw_t ** cred_p,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool)
- {
- auth_cred_ssl_client_cert_pw_t * cred = NULL;
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- const char * result = NULL;
- WEBDAV_ERR(fs->AskForPassphrase(&result, realm, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- cred = static_cast<auth_cred_ssl_client_cert_pw_t *>(apr_pcalloc(pool, sizeof(*cred)));
- cred->password = result;
- cred->may_save = may_save;
- *cred_p = cred;
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_simple_prompt_func_t'.
- static error_t
- cmdline_auth_simple_prompt(
- auth_cred_simple_t ** cred_p,
- void * baton,
- const char * realm,
- const char * username,
- bool may_save,
- apr_pool_t * pool)
- {
- auth_cred_simple_t * ret =
- static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*ret)));
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- if (username)
- ret->username = apr_pstrdup(pool, username);
- else
- {
- WEBDAV_ERR(fs->AskForUsername(&ret->username, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- }
- WEBDAV_ERR(fs->AskForUserPassword(&ret->password, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- ret->may_save = may_save;
- *cred_p = ret;
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_username_prompt_func_t'.
- static error_t
- cmdline_auth_username_prompt(
- auth_cred_username_t ** cred_p,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool)
- {
- auth_cred_username_t * ret =
- static_cast<auth_cred_username_t *>(apr_pcalloc(pool, sizeof(*ret)));
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- WEBDAV_ERR(fs->AskForUsername(&ret->username, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- ret->may_save = may_save;
- *cred_p = ret;
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from cmdline.c
- static error_t
- ssl_trust_unknown_server_cert(
- auth_cred_ssl_server_trust_t ** cred_p,
- void * baton,
- const char * realm,
- apr_uint32_t failures,
- const auth_ssl_server_cert_info_t * cert_info,
- bool may_save,
- apr_pool_t * pool)
- {
- *cred_p = NULL;
- if (failures == 0 || failures == WEBDAV_AUTH_SSL_UNKNOWNCA)
- {
- *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->may_save = FALSE;
- (*cred_p)->accepted_failures = failures;
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_baton_init(
- auth_baton_t * ab,
- bool non_interactive,
- const char * auth_username,
- const char * auth_password,
- bool no_auth_cache,
- bool trust_server_cert,
- TWebDAVFileSystem * fs,
- cancel_func_t cancel_func,
- void * cancel_baton,
- apr_pool_t * pool)
- {
- bool store_password_val = TRUE;
- bool store_auth_creds_val = TRUE;
- auth_provider_object_t * provider = NULL;
- cmdline_prompt_baton2_t * pb = NULL;
- // The whole list of registered providers
- apr_array_header_t * providers = NULL;
- // Populate the registered providers with the platform-specific providers
- WEBDAV_ERR(auth_get_platform_specific_client_providers(&providers,
- pool));
- // If we have a cancellation function, cram it and the stuff it
- // needs into the prompt baton.
- if (cancel_func)
- {
- pb = static_cast<cmdline_prompt_baton2_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->cancel_func = cancel_func;
- pb->cancel_baton = cancel_baton;
- }
- if (non_interactive == FALSE)
- {
- // This provider doesn't prompt the user in order to get creds;
- // it prompts the user regarding the caching of creds.
- auth_get_simple_provider2(&provider,
- cmdline_auth_plaintext_prompt,
- pb, pool);
- }
- else
- {
- auth_get_simple_provider2(&provider, NULL, NULL, pool);
- }
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_username_provider(&provider, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- // The server-cert, client-cert, and client-cert-password providers.
- WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
- "windows",
- "ssl_server_trust",
- pool));
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_ssl_server_trust_file_provider(&provider, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_ssl_client_cert_file_provider(&provider, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- if (non_interactive == FALSE)
- {
- // This provider doesn't prompt the user in order to get creds;
- // it prompts the user regarding the caching of creds.
- auth_get_ssl_client_cert_pw_file_provider2(&provider, cmdline_auth_plaintext_passphrase_prompt,
- pb, pool);
- }
- else
- {
- auth_get_ssl_client_cert_pw_file_provider2(&provider, NULL, NULL,
- pool);
- }
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- if (non_interactive == FALSE)
- {
- // Two basic prompt providers: username/password, and just username.
- auth_get_simple_prompt_provider(&provider,
- cmdline_auth_simple_prompt,
- pb,
- 2, // retry limit
- pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_username_prompt_provider(&provider, cmdline_auth_username_prompt, pb,
- 2, /* retry limit */ pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- // Three ssl prompt providers, for server-certs, client-certs,
- // and client-cert-passphrases.
- auth_get_ssl_server_trust_prompt_provider(&provider, cmdline_auth_ssl_server_trust_prompt, pb, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_ssl_client_cert_prompt_provider(&provider, cmdline_auth_ssl_client_cert_prompt, pb, 2, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_ssl_client_cert_pw_prompt_provider(&provider, cmdline_auth_ssl_client_cert_pw_prompt, pb, 2, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- }
- else if (trust_server_cert)
- {
- // Remember, only register this provider if non_interactive.
- auth_get_ssl_server_trust_prompt_provider(&provider, ssl_trust_unknown_server_cert, NULL, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- }
- // Build an authentication baton to give to libclient.
- create_baton_open(ab, providers, pool);
- auth_baton_set_parameter(ab, CONST_FS_KEY, fs);
- // Place any default username or password credentials into the
- // auth_baton's run-time parameter hash.
- if (auth_username)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- auth_username);
- if (auth_password)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
- auth_password);
- // Same with the non-interactive option.
- if (non_interactive)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_NON_INTERACTIVE, "");
- if (!store_password_val)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
- if (no_auth_cache || !store_auth_creds_val)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_NO_AUTH_CACHE, "");
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from main.c
- // A flag to see if we've been canceled by the client or not.
- static volatile atomic_t cancelled = FALSE;
- // Our cancellation callback.
- static error_t
- check_cancel(void * baton)
- {
- if (cancelled)
- return error_create(WEBDAV_ERR_CANCELLED, NULL, "Cancelled");
- else
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from ra.c
- static error_t
- cancel_callback(void * baton)
- {
- callback_baton_t * cb = static_cast<callback_baton_t *>(baton);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- cancelled = static_cast<atomic_t>(fs->GetIsCancelled());
- return error_trace((cb->ctx->cancel_func)(cb->ctx->cancel_baton));
- }
- static error_t
- get_client_string(
- void * baton,
- const char ** name,
- apr_pool_t * pool)
- {
- callback_baton_t * b = static_cast<callback_baton_t *>(baton);
- *name = apr_pstrdup(pool, b->ctx->client_name);
- return WEBDAV_NO_ERROR;
- }
- // see ra.c::client_session_from_path
- static error_t
- init_session_from_path(
- session_t * session,
- const char ** url_p,
- const char * path_or_url,
- apr_pool_t * pool)
- {
- const char * initial_url, *url;
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- WEBDAV_ERR(client_url_from_path2(&initial_url, path_or_url,
- ras->url, pool, pool));
- if (!initial_url)
- return error_createf(WEBDAV_ERR_ENTRY_MISSING_URL, NULL,
- "'%s' has no URL", path_or_url);
- url = initial_url;
- // Make the session point to the real URL.
- WEBDAV_ERR(reparent(session, url, pool));
- *url_p = url;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_open_session_internal(
- session_t ** ra_session,
- const char ** corrected_url,
- const char * base_url,
- client_ctx_t * ctx,
- apr_pool_t * pool)
- {
- // prepare callbacks, contexts
- callbacks2_t * cbtable = static_cast<callbacks2_t *>(apr_pcalloc(pool, sizeof(*cbtable)));
- callback_baton_t * cb = static_cast<callback_baton_t *>(apr_pcalloc(pool, sizeof(*cb)));
- cbtable->auth_baton = ctx->auth_baton;
- cbtable->progress_func = ctx->progress_func;
- cbtable->progress_baton = ctx->progress_baton;
- cbtable->cancel_func = ctx->cancel_func ? cancel_callback : NULL;
- cbtable->get_client_string = get_client_string;
- cb->pool = pool;
- cb->ctx = ctx;
- if (corrected_url)
- {
- apr_hash_t * attempted = apr_hash_make(pool);
- int attempts_left = MAX_REDIRECT_ATTEMPTS;
- while (attempts_left--)
- {
- const char * corrected = NULL;
- WEBDAV_ERR(session_open(
- ra_session,
- attempts_left == 0 ? NULL : &corrected,
- base_url, cbtable, cb,
- pool));
- // No error and no corrected URL? We're done here.
- if (!corrected)
- break;
- // Our caller will want to know what our final corrected URL was.
- *corrected_url = corrected;
- // Make sure we've not attempted this URL before.
- if (apr_hash_get(attempted, corrected, APR_HASH_KEY_STRING))
- return WEBDAV_ERR_CLIENT_CYCLE_DETECTED;
- // Remember this CORRECTED_URL so we don't wind up in a loop.
- apr_hash_set(attempted, apr_pstrdup(pool, corrected), APR_HASH_KEY_STRING, (void *)1);
- base_url = corrected;
- }
- }
- else
- {
- WEBDAV_ERR(session_open(ra_session, NULL, base_url,
- cbtable, cb,
- pool));
- }
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from list.c
- static error_t
- get_dir_contents(
- apr_uint32_t dirent_fields,
- const char * dir,
- session_t * ra_session,
- const char * fs_path,
- depth_t depth,
- client_list_func_t list_func,
- void * baton,
- apr_pool_t * pool)
- {
- apr_hash_t * tmpdirents = NULL;
- apr_pool_t * iterpool = webdav_pool_create(pool);
- apr_array_header_t * array = NULL;
- error_t err = 0;
- if (depth == depth_empty)
- return WEBDAV_NO_ERROR;
- // Get the directory's entries, but not its props. Ignore any
- // not-authorized errors.
- err = get_dir2(ra_session, &tmpdirents,
- dir,
- dirent_fields, pool);
- if (err && ((err == WEBDAV_ERR_NOT_AUTHORIZED) ||
- (err == WEBDAV_ERR_DAV_FORBIDDEN)))
- {
- error_clear(&err);
- return WEBDAV_NO_ERROR;
- }
- WEBDAV_ERR(err);
- neon_session_t * ras = static_cast<neon_session_t *>(ra_session->priv);
- assert(ras);
- if (ras->callbacks->cancel_func)
- WEBDAV_ERR(ras->callbacks->cancel_func(ras->callback_baton));
- // Sort the hash, so we can call the callback in a "deterministic" order.
- array = sort_hash(tmpdirents, sort_compare_items_lexically, pool);
- for (int i = 0; i < array->nelts; ++i)
- {
- sort_item_t * item = &APR_ARRAY_IDX(array, i, sort_item_t);
- dirent_t * the_ent = static_cast<dirent_t *>(apr_hash_get(tmpdirents, item->key, item->klen));
- webdav_pool_clear(iterpool);
- const char * path = relpath_join(dir, static_cast<const char *>(item->key), iterpool);
- if ((the_ent->kind == node_file) ||
- (depth == depth_immediates) ||
- (depth == depth_infinity))
- WEBDAV_ERR(list_func(baton, path,
- the_ent,
- fs_path, iterpool));
- if (depth == depth_infinity && the_ent->kind == node_dir)
- WEBDAV_ERR(get_dir_contents(dirent_fields, path,
- ra_session,
- fs_path, depth,
- list_func, baton, iterpool));
- }
- webdav_pool_destroy(iterpool);
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from options.c
- static const neon_xml_elm_t options_elements[] =
- {
- { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
- { "DAV:", "options-response", ELEM_options_response, 0 },
- { NULL }
- };
- typedef struct options_ctx_t
- {
- // WARNING: WANT_CDATA should stay the first element in the baton:
- // neon_xml_collect_cdata() assumes the baton starts with a stringbuf.
- stringbuf_t * want_cdata;
- stringbuf_t * cdata;
- apr_pool_t * pool;
- } options_ctx_t;
- static int
- options_validate_element(
- neon_xml_elmid parent,
- neon_xml_elmid child)
- {
- switch (parent)
- {
- case ELEM_root:
- if (child == ELEM_options_response)
- return child;
- else
- return NEON_XML_INVALID;
- case ELEM_options_response:
- return NEON_XML_DECLINE; // not concerned with other response
- default:
- return NEON_XML_DECLINE;
- }
- // NOTREACHED
- }
- static error_t
- options_start_element(
- int * elem,
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- options_ctx_t * oc = static_cast<options_ctx_t *>(baton);
- const neon_xml_elm_t * elm = neon_lookup_xml_elem(options_elements, nspace, name);
- *elem = elm ? options_validate_element(parent, elm->id) : NEON_XML_DECLINE;
- if (*elem < 1) // Not a valid element
- return WEBDAV_NO_ERROR;
- if (elm->id == ELEM_href)
- oc->want_cdata = oc->cdata;
- else
- oc->want_cdata = NULL;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- options_end_element(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_exchange_capabilities(
- neon_session_t * ras,
- const char ** relocation_location,
- apr_pool_t * pool)
- {
- neon_request_t * req = NULL;
- error_t err = WEBDAV_NO_ERROR;
- ne_xml_parser * parser = NULL;
- options_ctx_t oc = { 0 };
- int status_code = 0;
- oc.pool = pool;
- oc.cdata = stringbuf_create("", pool);
- if (relocation_location)
- *relocation_location = NULL;
- WEBDAV_ERR(neon_request_create(&req, ras,
- "OPTIONS", ras->url->data, pool));
- // Use a symbolic name somewhere for this MIME type?
- ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
- apr_hash_t * extra_headers = apr_hash_make(pool);
- neon_add_depth_header(extra_headers, NEON_DEPTH_ZERO);
- // Create a parser to read the normal response body
- parser = neon_xml_parser_create(req, ne_accept_2xx, options_start_element,
- neon_xml_collect_cdata,
- options_end_element, &oc);
- // Run the request and get the resulting status code.
- if ((err = neon_request_dispatch(&status_code, req, extra_headers,
- "<?xml version=\"1.0\" "
- "encoding=\"utf-8\"?>"
- "<D:options xmlns:D=\"DAV:\">"
- "<D:resourcetype/>"
- "</D:options>",
- 200,
- relocation_location ? 301 : 0,
- false,
- pool)) != WEBDAV_NO_ERROR)
- goto cleanup;
- if (req->code == 301)
- {
- *relocation_location = neon_request_get_location(req, pool);
- goto cleanup;
- }
- // Was there an XML parse error somewhere?
- err = neon_check_parse_error("OPTIONS", parser, ras->url->data);
- if (err)
- goto cleanup;
- cleanup:
- neon_request_destroy(req);
- return err;
- }
- //------------------------------------------------------------------------------
- // from props.c
- typedef struct propfind_ctx_t
- {
- // WARNING: WANT_CDATA should stay the first element in the baton:
- // neon_xml_collect_cdata() assumes the baton starts with a stringbuf.
- stringbuf_t * cdata;
- apr_hash_t * props; // const char *URL-PATH -> neon_resource_t
- neon_resource_t * rsrc; // the current resource.
- const char * encoding; // property encoding (or NULL)
- int status; // status for the current <propstat> (or 0 if unknown).
- apr_hash_t * propbuffer; // holds properties until their status is known.
- neon_xml_elmid last_open_id; // the id of the last opened tag.
- ne_xml_parser * parser; // xml parser handling the PROPSET request.
- apr_pool_t * pool;
- } propfind_ctx_t;
- // When we begin a checkout, we fetch these from the "public" resources.
- // We fetch the resourcetype to
- // verify that we're accessing a collection.
- static const ne_propname starting_props[] =
- {
- { "DAV:", "resourcetype" },
- { "DAV:", "creationdate" },
- { "DAV:", "getlastmodified" },
- { "DAV:", "getcontentlength" },
- { NULL }
- };
- static error_t
- neon_get_starting_props(
- neon_resource_t ** rsrc,
- neon_session_t * sess,
- const char * url,
- bool check_errors,
- apr_pool_t * pool)
- {
- WEBDAV_ERR(neon_get_props_resource(rsrc, sess, url,
- starting_props, check_errors, pool));
- // Cache some of the resource information.
- if (!sess->webdav_root)
- {
- string_t * propval = NULL;
- if (propval)
- {
- ne_uri uri = {0};
- stringbuf_t * urlbuf = stringbuf_create(url, pool);
- path_remove_components(urlbuf,
- path_component_count(propval->data));
- uri = sess->root;
- uri.path = urlbuf->data;
- sess->webdav_root = neon_uri_unparse(&uri, sess->pool);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- // Propfind Implementation
- typedef struct elem_defn
- {
- neon_xml_elmid id;
- const char * name;
- int is_property; // is it a property, or part of some structure?
- } elem_defn;
- static const elem_defn elem_definitions[] =
- {
- // NOTE: Make sure that every item in here is also represented in
- // propfind_elements[]
- // DAV elements
- { ELEM_multistatus, "DAV:multistatus", 0 },
- { ELEM_response, "DAV:response", 0 },
- { ELEM_href, "DAV:href", NEON_XML_CDATA },
- { ELEM_propstat, "DAV:propstat", 0 },
- { ELEM_prop, "DAV:prop", 0 },
- { ELEM_status, "DAV:status", NEON_XML_CDATA },
- { ELEM_collection, "DAV:collection", NEON_XML_CDATA },
- { ELEM_resourcetype, "DAV:resourcetype", 0 },
- { ELEM_get_content_length, NEON_PROP_GETCONTENTLENGTH, 1 },
- { ELEM_creationdate, NEON_PROP_CREATIONDATE, 1 },
- { 0 }
- };
- static const neon_xml_elm_t propfind_elements[] =
- {
- // NOTE: Make sure that every item in here is also represented in
- // elem_definitions[]
- // DAV elements
- { "DAV:", "multistatus", ELEM_multistatus, 0 },
- { "DAV:", "response", ELEM_response, 0 },
- { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
- { "DAV:", "propstat", ELEM_propstat, 0 },
- { "DAV:", "prop", ELEM_prop, 0 },
- { "DAV:", "status", ELEM_status, NEON_XML_CDATA },
- { "DAV:", "collection", ELEM_collection, NEON_XML_CDATA },
- { "DAV:", "resourcetype", ELEM_resourcetype, 0 },
- { "DAV:", "getcontentlength", ELEM_get_content_length, NEON_XML_CDATA },
- { "DAV:", "getlastmodified", ELEM_get_last_modified, NEON_XML_CDATA },
- {
- "DAV:", "creator-displayname", ELEM_creator_displayname,
- NEON_XML_CDATA
- },
- // Unknowns
- { "", "", ELEM_unknown, NEON_XML_COLLECT },
- { NULL }
- };
- // Look up an element definition ID. May return NULL if the elem is
- // not recognized.
- static const elem_defn *
- defn_from_id(
- neon_xml_elmid id)
- {
- for (const elem_defn * defn = elem_definitions; defn->name != NULL; ++defn)
- {
- if (id == defn->id)
- return defn;
- }
- return NULL;
- }
- // Assign URL to RSRC. Use POOL for any allocations.
- static error_t
- assign_rsrc_url(
- neon_resource_t * rsrc,
- const char * url,
- apr_pool_t * pool)
- {
- char * url_path = NULL;
- apr_size_t len = 0;
- ne_uri parsed_url = {0};
- // Parse the PATH element out of the URL.
- // NOTE: mod_dav does not (currently) use an absolute URL, but simply a
- // server-relative path (i.e. this uri_parse is effectively a no-op).
- if (ne_uri_parse(url, &parsed_url) != 0)
- {
- ne_uri_free(&parsed_url);
- return error_createf(WEBDAV_ERR_DAV_MALFORMED_DATA, NULL,
- "Unable to parse URL '%s'", url);
- }
- url_path = apr_pstrdup(pool, parsed_url.path);
- ne_uri_free(&parsed_url);
- // Clean up trailing slashes from the URL.
- len = strlen(url_path);
- if ((len > 1) && (url_path[len - 1] == '/'))
- url_path[len - 1] = '\0';
- rsrc->url = url_path;
- return WEBDAV_NO_ERROR;
- }
- // Determine whether we're receiving the expected XML response.
- // Return CHILD when interested in receiving the child's contents
- // or one of NEON_XML_INVALID and NEON_XML_DECLINE
- // when respectively this is the incorrect response or
- // the element (and its children) are uninteresting
- static int
- props_validate_element(
- neon_xml_elmid parent,
- neon_xml_elmid child)
- {
- switch (parent)
- {
- case ELEM_root:
- if (child == ELEM_multistatus)
- return child;
- else
- return NEON_XML_INVALID;
- case ELEM_multistatus:
- if (child == ELEM_response)
- return child;
- else
- return NEON_XML_DECLINE;
- case ELEM_response:
- if ((child == ELEM_href) || (child == ELEM_propstat))
- return child;
- else
- return NEON_XML_DECLINE;
- case ELEM_propstat:
- if ((child == ELEM_prop) || (child == ELEM_status))
- return child;
- else
- return NEON_XML_DECLINE;
- case ELEM_prop:
- return child; // handle all children of <prop>
- case ELEM_resourcetype:
- if (child == ELEM_collection)
- return child;
- else
- return NEON_XML_DECLINE; // not concerned with other types (now)
- default:
- return NEON_XML_DECLINE;
- }
- // NOTREACHED
- }
- static error_t
- props_start_element(
- int * elem,
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
- const neon_xml_elm_t * elm = neon_lookup_xml_elem(propfind_elements, nspace, name);
- *elem = elm ? props_validate_element(parent, elm->id) : NEON_XML_DECLINE;
- if (*elem < 1) // not a valid element
- return WEBDAV_NO_ERROR;
- stringbuf_setempty(pc->cdata);
- *elem = elm ? elm->id : ELEM_unknown;
- switch (*elem)
- {
- case ELEM_response:
- if (pc->rsrc)
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- // Create a new resource.
- pc->rsrc = static_cast<neon_resource_t *>(apr_pcalloc(pc->pool, sizeof(*(pc->rsrc))));
- pc->rsrc->pool = pc->pool;
- pc->rsrc->propset = apr_hash_make(pc->pool);
- pc->status = 0;
- break;
- case ELEM_propstat:
- pc->status = 0;
- break;
- case ELEM_href:
- pc->rsrc->href_parent = pc->last_open_id;
- break;
- case ELEM_collection:
- pc->rsrc->is_collection = 1;
- break;
- case ELEM_unknown:
- // these are our user-visible properties, presumably.
- if (pc->encoding)
- pc->encoding = apr_pstrdup(pc->pool, pc->encoding);
- break;
- default:
- // nothing to do for these
- break;
- }
- // Remember the last tag we opened.
- pc->last_open_id = *elem;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- props_end_element(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
- neon_resource_t * rsrc = pc->rsrc;
- const string_t * value = NULL;
- const elem_defn * parent_defn = NULL;
- const elem_defn * defn = NULL;
- ne_status status = {0};
- const char * cdata = pc->cdata->data;
- switch (state)
- {
- case ELEM_response:
- // Verify that we've received a URL for this resource.
- if (!pc->rsrc->url)
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- // Store the resource in the top-level hash table.
- apr_hash_set(pc->props, pc->rsrc->url, APR_HASH_KEY_STRING, pc->rsrc);
- pc->rsrc = NULL;
- return WEBDAV_NO_ERROR;
- case ELEM_propstat:
- // We're at the end of a set of properties. Do the right thing status-wise.
- if (pc->status)
- {
- for (apr_hash_index_t * hi = apr_hash_first(pc->pool, pc->propbuffer); hi;
- hi = apr_hash_next(hi))
- {
- const void * key;
- apr_ssize_t klen;
- void * val;
- apr_hash_this(hi, &key, &klen, &val);
- if (pc->status == 200)
- apr_hash_set(rsrc->propset, key, klen, val);
- apr_hash_set(pc->propbuffer, key, klen, NULL);
- }
- }
- else if (!pc->status)
- {
- // No status at all? Bogosity.
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- }
- return WEBDAV_NO_ERROR;
- case ELEM_status:
- // Parse the <status> tag's CDATA for a status code.
- if (ne_parse_statusline(cdata, &status))
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- ne_free(status.reason_phrase);
- pc->status = status.code;
- return WEBDAV_NO_ERROR;
- case ELEM_href:
- // Special handling for <href> that belongs to the <response> tag.
- if (rsrc->href_parent == ELEM_response)
- return assign_rsrc_url(pc->rsrc,
- urlpath_canonicalize(cdata, pc->pool),
- pc->pool);
- // Use the parent element's name, not the href.
- parent_defn = defn_from_id(rsrc->href_parent);
- // No known parent? Get outta here.
- if (!parent_defn)
- return WEBDAV_NO_ERROR;
- // All other href's we'll treat as property values.
- name = parent_defn->name;
- value = string_create(urlpath_canonicalize(cdata, pc->pool),
- pc->pool);
- break;
- default:
- if (state == ELEM_unknown)
- {
- name = apr_pstrcat(pc->pool, nspace, name, (char *)NULL);
- }
- else
- {
- defn = defn_from_id(state);
- if (!(defn && defn->is_property))
- return WEBDAV_NO_ERROR;
- name = defn->name;
- }
- // Check for encoding attribute.
- if (pc->encoding == NULL)
- {
- // Handle the property value by converting it to string.
- value = string_create(cdata, pc->pool);
- break;
- }
- // Check for known encoding type
- if (strcmp(pc->encoding, "base64") != 0)
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- pc->encoding = NULL; // Reset encoding for future attribute(s).
- }
- // Handling resource properties from here out.
- // Add properties to the temporary propbuffer. At the end of the
- // <propstat>, we'll either dump the props as invalid or move them
- // into the resource's property hash.
- apr_hash_set(pc->propbuffer, name, APR_HASH_KEY_STRING, value);
- return WEBDAV_NO_ERROR;
- }
- static void
- props_set_parser(
- ne_xml_parser * parser,
- void * baton)
- {
- propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
- pc->parser = parser;
- }
- static error_t
- neon_get_props(
- apr_hash_t ** results,
- neon_session_t * sess,
- const char * url,
- int depth,
- const ne_propname * which_props,
- bool check_errors,
- apr_pool_t * pool)
- {
- apr_hash_t * extra_headers = apr_hash_make(pool);
- neon_add_depth_header(extra_headers, depth);
- // It's easier to roll our own PROPFIND here than use neon's current interfaces.
- // The start of the request body is fixed:
- stringbuf_t * body = stringbuf_create("<?xml version=\"1.0\" encoding=\"utf-8\"?>" DEBUG_CR
- "<propfind xmlns=\"DAV:\">" DEBUG_CR, pool);
- // Are we asking for specific propert(y/ies), or just all of them?
- if (which_props)
- {
- apr_pool_t * iterpool = webdav_pool_create(pool);
- stringbuf_appendcstr(body, "<prop>" DEBUG_CR);
- for (int n = 0; which_props[n].name != NULL; n++)
- {
- webdav_pool_clear(iterpool);
- stringbuf_appendcstr(body, apr_pstrcat(iterpool, "<", which_props[n].name,
- " xmlns=\"", which_props[n].nspace, "\"/>" DEBUG_CR,
- (char *)NULL));
- }
- stringbuf_appendcstr(body, "</prop></propfind>" DEBUG_CR);
- webdav_pool_destroy(iterpool);
- }
- else
- {
- stringbuf_appendcstr(body, "<allprop/></propfind>" DEBUG_CR);
- }
- // Initialize our baton.
- propfind_ctx_t pc;
- memset(&pc, 0, sizeof(pc));
- pc.pool = pool;
- pc.propbuffer = apr_hash_make(pool);
- pc.props = apr_hash_make(pool);
- pc.cdata = stringbuf_create("", pool);
- // Create and dispatch the request!
- WEBDAV_ERR(neon_parsed_request(sess, "PROPFIND", url,
- body->data, 0,
- props_set_parser,
- props_start_element,
- neon_xml_collect_cdata,
- props_end_element,
- &pc, extra_headers, NULL,
- check_errors,
- pool));
- *results = pc.props;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_get_props_resource(
- neon_resource_t ** rsrc,
- neon_session_t * sess,
- const char * url,
- const ne_propname * which_props,
- bool check_errors,
- apr_pool_t * pool)
- {
- apr_hash_t * props = NULL;
- char * url_path = apr_pstrdup(pool, url);
- apr_size_t len = strlen(url);
- // Clean up any trailing slashes.
- if ((len > 1) && (url[len - 1] == '/'))
- url_path[len - 1] = '\0';
- WEBDAV_ERR(neon_get_props(&props, sess, url_path, NEON_DEPTH_ZERO,
- which_props, check_errors, pool));
- // HACK. We need to have the client canonicalize paths, get rid
- // of double slashes and such. This check is just a check against
- // non-SVN servers; in the long run we want to re-enable this.
- {
- // pick out the first response: the URL requested will not match
- // the response href.
- apr_hash_index_t * hi = apr_hash_first(pool, props);
- if (hi)
- {
- void * ent;
- apr_hash_this(hi, NULL, NULL, &ent);
- *rsrc = static_cast<neon_resource_t *>(ent);
- }
- else
- *rsrc = NULL;
- }
- if (*rsrc == NULL)
- {
- // hmmm, should have been in there...
- return error_createf(APR_EGENERAL, NULL,
- "Failed to find label '%s' for URL '%s'",
- "NULL", url_path);
- }
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- static error_t
- client_list2(
- session_t * session,
- const char * path_or_url,
- depth_t depth,
- apr_uint32_t dirent_fields,
- client_list_func_t list_func,
- void * baton,
- apr_pool_t * pool)
- {
- dirent_t * dirent = NULL;
- const char * url = NULL;
- const char * webdav_root = NULL;
- const char * fs_path = NULL;
- error_t err = 0;
- assert(session);
- // We use the kind field to determine if we should recurse, so we
- // always need it.
- dirent_fields |= WEBDAV_DIRENT_KIND;
- WEBDAV_ERR(init_session_from_path(session,
- &url, path_or_url,
- pool));
- WEBDAV_ERR(get_webdav_resource_root2(session, &webdav_root, pool));
- WEBDAV_ERR(client_path_relative_to_root(&fs_path,
- url,
- webdav_root, TRUE, session,
- pool, pool));
- err = stat(session, "", &dirent, pool);
- if (err)
- return error_trace(err);
- if (!dirent)
- return error_createf(WEBDAV_ERR_FS_NOT_FOUND, NULL,
- "URL '%s' non-existent",
- url);
- // Report the dirent for the target.
- WEBDAV_ERR(list_func(baton, "", dirent, fs_path, pool));
- if (dirent->kind == node_dir && (depth == depth_files ||
- depth == depth_immediates ||
- depth == depth_infinity))
- {
- WEBDAV_ERR(get_dir_contents(dirent_fields, "",
- session,
- fs_path, depth,
- list_func, baton, pool));
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_get_file(
- session_t * session,
- const char * remote_path,
- apr_os_file_t * thefile,
- apr_pool_t * pool)
- {
- const char * remote_url = NULL;
- WEBDAV_ERR(init_session_from_path(session,
- &remote_url, path_uri_encode(remote_path, pool),
- pool));
- stream_t * fstream = NULL;
- WEBDAV_ERR(stream_open_writable(&fstream, thefile,
- pool, pool));
- const char * src_rel = NULL;
- WEBDAV_ERR(get_path_relative_to_session(session, &src_rel,
- remote_url,
- pool));
- WEBDAV_ERR(get_file(session, src_rel, fstream, NULL, pool));
- WEBDAV_ERR(stream_close(fstream));
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_put_file(
- session_t * session,
- const char * remote_path,
- const char * local_path,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- int code = 0;
- apr_hash_t * extra_headers = NULL; // apr_hash_make(pool);
- neon_request_t * request = NULL;
- const char * put_target = path_uri_encode(remote_path, pool);
- apr_file_t * body_file = NULL;
- WEBDAV_ERR(io_file_open(&body_file, local_path, APR_READ | APR_BUFFERED | APR_BINARY,
- APR_OS_DEFAULT, pool));
- // create/prep the request
- WEBDAV_ERR(neon_request_create(&request, ras, "PUT",
- put_target, pool));
- // Give the file to neon. The provider will rewind the file.
- err = neon_set_neon_body_provider(request, body_file);
- if (err)
- goto cleanup;
- // run the request and get the resulting status code (and error_t)
- err = neon_request_dispatch(&code, request, extra_headers, NULL,
- 201 /* Created */,
- 204 /* No Content */,
- false,
- pool);
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_PUT_FILE, NULL,
- "Cannot create '%s'"
- " (Status %d on PUT Request)",
- put_target, code);
- }
- cleanup:
- neon_request_destroy(request);
- WEBDAV_ERR(err);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_move_file_or_directory(
- session_t * session,
- const char * remote_path_from,
- const char * remote_path_to,
- void * baton,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- const char * target_from = path_uri_encode(remote_path_from, pool);
- const char * target_to = path_uri_encode(remote_path_to, pool);
- int code = 0;
- apr_hash_t * extra_headers = apr_hash_make(pool);
- apr_hash_set(extra_headers, "Destination", APR_HASH_KEY_STRING, target_to);
- neon_add_depth_header(extra_headers, NEON_DEPTH_INFINITE);
- err = neon_simple_request(&code, ras, "MOVE", target_from,
- extra_headers, NULL,
- 201 /* Created */,
- 204 /* No Content */,
- pool);
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_MOVE, NULL,
- "Cannot move '%s' to '%s'"
- " (Status %d on MOVE Request)",
- target_from, target_to, code);
- }
- return err;
- }
- static error_t
- client_delete_file(
- session_t * session,
- const char * remote_path,
- void * baton,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- const char * target = path_uri_encode(remote_path, pool);
- int code = 0;
- err = neon_simple_request(&code, ras, "DELETE", target,
- NULL, NULL,
- 200,
- 204, // No Content
- pool);
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_DELETE_FILE, NULL,
- "Cannot delete '%s'"
- " (Status %d on DELETE Request)",
- target, code);
- }
- return err;
- }
- static error_t
- client_check_path(
- session_t * session,
- const char * remote_path,
- node_kind_t * kind,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- *kind = node_none;
- error_t err = 0;
- char * target = apr_pstrdup(pool, path_uri_encode(remote_path, pool));
- const char * rel_path = NULL;
- apr_size_t len = strlen(target);
- if ((len > 1) && ((target)[len - 1] == '/'))
- {
- (target)[len - 1] = '\0';
- }
- if (*target == '/')
- {
- // check if root has trailing slash
- apr_size_t len = strlen(ras->webdav_root);
- if ((len > 1) && ((ras->webdav_root)[len - 1] == '/'))
- {
- target++;
- }
- const char * abs_path = apr_pstrcat(pool, ras->webdav_root, target, NULL);
- err = get_path_relative_to_root(
- session,
- &rel_path,
- abs_path,
- pool);
- WEBDAV_ERR(err);
- }
- else
- {
- rel_path = target;
- }
- err = check_path(
- session,
- rel_path,
- kind,
- pool
- );
- return err;
- }
- static error_t
- client_make_directory(
- session_t * session,
- const char * remote_path,
- void * baton,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- const char * target = path_uri_encode(remote_path, pool);
- int code = 0;
- err = neon_simple_request(
- &code, ras, "MKCOL", target,
- NULL, NULL,
- 201, 207, pool);
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_MKCOL, NULL,
- "Cannot create directory '%s'"
- " (Status %d on MKCOL Request)",
- target, code);
- }
- return err;
- }
- static error_t
- client_send_propfind_request(
- session_t * session,
- const char * remote_path,
- int * response_code,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- int code = 0;
- apr_hash_t * props = NULL;
- const char * target = path_uri_encode(remote_path, pool);
- char * url_path = apr_pstrdup(pool, target);
- WEBDAV_ERR(neon_get_props(&props, ras, url_path, NEON_DEPTH_ZERO,
- starting_props,
- false,
- pool));
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_PROPFIND, NULL,
- "Cannot execute PROPFIND on '%s'"
- " (Status %d on PROPFIND Request)",
- target, code);
- }
- if (response_code)
- *response_code = code;
- return err;
- }
- //------------------------------------------------------------------------------
- // from session.c
- typedef struct neonprogress_baton_t
- {
- neon_session_t * ras;
- apr_off_t last_progress;
- apr_time_t last_progress_time;
- apr_pool_t * pool;
- } neonprogress_baton_t;
- // Callback invoked to enter PKCS#11 PIN code.
- static int
- client_ssl_pkcs11_pin_entry(
- void * userdata,
- int attempt,
- const char * slot_descr,
- const char * token_label,
- unsigned int flags,
- char * pin)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(userdata);
- void * creds = NULL;
- auth_cred_ssl_client_cert_pw_t * pw_creds = NULL;
- // Always prevent PIN caching.
- auth_baton_set_parameter(ras->callbacks->auth_baton,
- AUTH_PARAM_NO_AUTH_CACHE, "");
- error_t err = 0;
- if (attempt == 0)
- {
- const char * realmstring;
- realmstring = apr_psprintf(ras->pool,
- "PIN for token \"%s\" in slot \"%s\"",
- token_label, slot_descr);
- err = auth_first_credentials(&creds,
- &(ras->auth_iterstate),
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- realmstring,
- ras->callbacks->auth_baton,
- ras->pool);
- }
- else
- {
- err = auth_next_credentials(&creds, ras->auth_iterstate, ras->pool);
- }
- if (err || !creds)
- {
- error_clear(&err);
- return -1;
- }
- pw_creds = static_cast<auth_cred_ssl_client_cert_pw_t *>(creds);
- strncpy(pin, pw_creds->password, NE_SSL_P11PINLEN);
- return 0;
- }
- static bool
- client_ssl_decrypt_cert(
- neon_session_t * ras,
- const char * cert_file,
- ne_ssl_client_cert * clicert)
- {
- auth_iterstate_t * state = NULL;
- error_t error = 0;
- apr_pool_t * pool = NULL;
- bool ok = false;
- void * creds = NULL;
- int try_count = 0;
- apr_pool_create(&pool, ras->pool);
- for (try_count = 0; TRUE; ++try_count)
- {
- if (try_count == 0)
- {
- error = auth_first_credentials(&creds, &state,
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- cert_file,
- ras->callbacks->auth_baton,
- pool);
- }
- else
- {
- error = auth_next_credentials(&creds, state, pool);
- }
- if (error || !creds)
- {
- // Failure or too many attempts
- error_clear(&error);
- break;
- }
- else
- {
- auth_cred_ssl_client_cert_pw_t * pw_creds = static_cast<auth_cred_ssl_client_cert_pw_t *>(creds);
- if (ne_ssl_clicert_decrypt(clicert, pw_creds->password) == 0)
- {
- error = auth_save_credentials(state, pool);
- if (error)
- error_clear(&error);
- // Success
- ok = TRUE;
- break;
- }
- }
- }
- webdav_pool_destroy(pool);
- return ok;
- }
- static void
- client_ssl_callback(
- void * userdata,
- ne_session * sess,
- const ne_ssl_dname * const * dnames,
- int dncount)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(userdata);
- ne_ssl_client_cert * clicert = NULL;
- void * creds = NULL;
- auth_iterstate_t * state = NULL;
- const char * realmstring = NULL;
- apr_pool_t * pool = NULL;
- error_t error = 0;
- int try_count = 0;
- apr_pool_create(&pool, ras->pool);
- realmstring = apr_psprintf(pool, "%s://%s:%d", ras->root.scheme,
- ras->root.host, ras->root.port);
- for (try_count = 0; TRUE; ++try_count)
- {
- if (try_count == 0)
- {
- error = auth_first_credentials(&creds, &state,
- AUTH_CRED_SSL_CLIENT_CERT,
- realmstring,
- ras->callbacks->auth_baton,
- pool);
- }
- else
- {
- error = auth_next_credentials(&creds, state, pool);
- }
- if (error || !creds)
- {
- // Failure or too many attempts
- error_clear(&error);
- break;
- }
- else
- {
- auth_cred_ssl_client_cert_t * client_creds = static_cast<auth_cred_ssl_client_cert_t *>(creds);
- clicert = ne_ssl_clicert_read(client_creds->cert_file);
- if (clicert)
- {
- if (!ne_ssl_clicert_encrypted(clicert) ||
- client_ssl_decrypt_cert(ras, client_creds->cert_file,
- clicert))
- {
- ne_ssl_set_clicert(sess, clicert);
- }
- ne_ssl_clicert_free(clicert);
- clicert = NULL;
- break;
- }
- }
- }
- webdav_pool_destroy(pool);
- }
- static const apr_uint32_t neon_failure_map[][2] =
- {
- { NE_SSL_NOTYETVALID, WEBDAV_AUTH_SSL_NOTYETVALID },
- { NE_SSL_EXPIRED, WEBDAV_AUTH_SSL_EXPIRED },
- { NE_SSL_IDMISMATCH, WEBDAV_AUTH_SSL_CNMISMATCH },
- { NE_SSL_UNTRUSTED, WEBDAV_AUTH_SSL_UNKNOWNCA }
- };
- // Convert neon's SSL failure mask to our own failure mask.
- static apr_uint32_t
- convert_neon_failures(
- int neon_failures)
- {
- apr_uint32_t failures = 0;
- for (apr_size_t i = 0; i < sizeof(neon_failure_map) / (2 * sizeof(int)); ++i)
- {
- if (neon_failures & neon_failure_map[i][0])
- {
- failures |= neon_failure_map[i][1];
- neon_failures &= ~neon_failure_map[i][0];
- }
- }
- // Map any remaining neon failure bits to our OTHER bit.
- if (neon_failures)
- {
- failures |= WEBDAV_AUTH_SSL_OTHER;
- }
- return failures;
- }
- // A neon-session callback to validate the SSL certificate when the CA
- // is unknown (e.g. a self-signed cert), or there are other SSL
- // certificate problems.
- static int
- server_ssl_callback(
- void * userdata,
- int failures,
- const ne_ssl_certificate * cert)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(userdata);
- auth_cred_ssl_server_trust_t * server_creds = NULL;
- void * creds = NULL;
- auth_iterstate_t * state = NULL;
- apr_pool_t * pool = NULL;
- error_t error = 0;
- char * ascii_cert = ne_ssl_cert_export(cert);
- char * issuer_dname = ne_ssl_readable_dname(ne_ssl_cert_issuer(cert));
- auth_ssl_server_cert_info_t cert_info = {0};
- char fingerprint[NE_SSL_DIGESTLEN] = {0};
- char valid_from[NE_SSL_VDATELEN] = {0}, valid_until[NE_SSL_VDATELEN] = {0};
- apr_uint32_t * webdav_failures = static_cast<apr_uint32_t *>(apr_pcalloc(ras->pool, sizeof(*webdav_failures)));
- // Construct the realmstring, e.g. https://svn.collab.net:80
- const char * realmstring = apr_pstrdup(ras->pool, Format("%s://%s:%d", ras->root.scheme,
- ras->root.host, ras->root.port).c_str());
- *webdav_failures = convert_neon_failures(failures);
- auth_baton_set_parameter(ras->callbacks->auth_baton,
- AUTH_PARAM_SSL_SERVER_FAILURES,
- webdav_failures);
- // Extract the info from the certificate
- cert_info.hostname = ne_ssl_cert_identity(cert);
- if (ne_ssl_cert_digest(cert, fingerprint) != 0)
- {
- strcpy(fingerprint, "<unknown>");
- }
- cert_info.fingerprint = fingerprint;
- ne_ssl_cert_validity(cert, valid_from, valid_until);
- cert_info.valid_from = valid_from;
- cert_info.valid_until = valid_until;
- cert_info.issuer_dname = issuer_dname;
- cert_info.ascii_cert = ascii_cert;
- auth_baton_set_parameter(ras->callbacks->auth_baton,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- &cert_info);
- apr_pool_create(&pool, ras->pool);
- error = auth_first_credentials(&creds, &state,
- AUTH_CRED_SSL_SERVER_TRUST,
- realmstring,
- ras->callbacks->auth_baton,
- pool);
- if (error || !creds)
- {
- error_clear(&error);
- }
- else
- {
- server_creds = static_cast<auth_cred_ssl_server_trust_t *>(creds);
- error = auth_save_credentials(state, pool);
- if (error)
- {
- // It would be nice to show the error to the user somehow...
- error_clear(&error);
- }
- }
- free(issuer_dname);
- free(ascii_cert);
- auth_baton_set_parameter(ras->callbacks->auth_baton,
- AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
- webdav_pool_destroy(pool);
- return !server_creds;
- }
- // An `ne_request_auth' callback, see ne_auth.h. USERDATA is a struct proxy_auth_baton_t *
- // If ATTEMPT < 10, copy USERDATA->username and USERDATA->password
- // into USERNAME and PASSWORD respectively (but do not copy more than
- // NE_ABUFSIZ bytes of either), and return zero to indicate to Neon
- // that authentication should be attempted.
- // If ATTEMPT >= 10, copy nothing into USERNAME and PASSWORD and
- // return 1, to cancel further authentication attempts.
- // Ignore REALM.
- static int
- proxy_auth(
- void * userdata,
- const char * realm,
- int attempt,
- char * username,
- char * password)
- {
- proxy_auth_baton_t * pab = static_cast<proxy_auth_baton_t *>(userdata);
- if (attempt >= 10)
- return 1;
- // Else.
- strncpy(username, pab->username, NE_ABUFSIZ);
- strncpy(password, pab->password, NE_ABUFSIZ);
- return 0;
- }
- // A neon-session callback to 'pull' authentication data when
- // challenged. In turn, this routine 'pulls' the data from the client
- // callbacks if needed.
- static int
- request_auth(
- void * userdata,
- const char * realm,
- int attempt,
- char * username,
- char * password)
- {
- error_t err = 0;
- neon_session_t * ras = static_cast<neon_session_t *>(userdata);
- void * creds = NULL;
- auth_cred_simple_t * simple_creds = NULL;
- // Start by marking the current credentials invalid.
- ras->auth_used = false;
- // No auth_baton? Give up.
- if (!ras->callbacks->auth_baton)
- return -1;
- // Neon automatically tries some auth protocols and bumps the attempt
- // count without using our callbacks, so we can't depend
- // on attempt == 0 the first time we are called -- we need to check
- // if the auth state has been initted as well.
- if (attempt == 0 || ras->auth_iterstate == NULL)
- {
- const char * realmstring = apr_psprintf(ras->pool, "<%s://%s:%d> %s",
- ras->root.scheme, ras->root.host,
- ras->root.port, realm);
- err = auth_first_credentials(&creds,
- &(ras->auth_iterstate),
- AUTH_CRED_SIMPLE,
- realmstring,
- ras->callbacks->auth_baton,
- ras->pool);
- }
- else // attempt > 0
- // TODO: if the http realm changed this time around, we
- // should be calling first_creds(), not next_creds().
- err = auth_next_credentials(&creds,
- ras->auth_iterstate,
- ras->pool);
- if (err || !creds)
- {
- error_clear(&err);
- return -1;
- }
- simple_creds = static_cast<auth_cred_simple_t *>(creds);
- // Make neon_request_dispatch store the credentials after it
- // sees a successful response
- ras->auth_used = true;
- // silently truncates username/password to 256 chars.
- if (simple_creds->username) strncpy(username, simple_creds->username, NE_ABUFSIZ);
- if (simple_creds->password) strncpy(password, simple_creds->password, NE_ABUFSIZ);
- return 0;
- }
- // a cleanup routine attached to the pool that contains the RA session baton.
- static apr_status_t
- cleanup_session(
- void * sess)
- {
- ne_session_destroy(static_cast<ne_session *>(sess));
- return APR_SUCCESS;
- }
- // a cleanup routine attached to the pool that contains the PKCS#11
- // provider object.
- static apr_status_t
- cleanup_p11provider(
- void * provider)
- {
- ne_ssl_pkcs11_provider * prov = static_cast<ne_ssl_pkcs11_provider *>(provider);
- ne_ssl_pkcs11_provider_destroy(prov);
- return APR_SUCCESS;
- }
- #ifdef NETBOX_DEBUG
- typedef struct debug_file_baton_t
- {
- FILE * file;
- } debug_file_baton_t;
- // a cleanup routine
- static apr_status_t
- cleanup_neon_debug_file(
- void * debug_file_baton)
- {
- debug_file_baton_t * baton = static_cast<debug_file_baton_t *>(debug_file_baton);
- if (baton->file) fclose(baton->file);
- return APR_SUCCESS;
- }
- #endif
- static void
- progress_func(
- apr_off_t progress,
- apr_off_t total,
- void * baton,
- apr_pool_t * pool)
- {
- client_ctx_t * ctx = static_cast<client_ctx_t *>(baton);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- if (total == -1)
- fs->ReadDirectoryProgress(progress);
- else
- fs->FileTransferProgress(total, progress);
- }
- static void
- ra_neon_neonprogress(
- void * baton,
- apr_off_t progress,
- apr_off_t total)
- {
- neonprogress_baton_t * pb = static_cast<neonprogress_baton_t *>(baton);
- neon_session_t * ras = pb->ras;
- if (ras->progress_func)
- {
- apr_time_t now = apr_time_now();
- if (now - pb->last_progress_time > 200000) // 0.2 sec
- {
- if (total < 0)
- {
- // Neon sends the total number of bytes sent for this specific
- // session and there are two sessions active at once.
- // For this case we combine the totals to allow clients to provide
- // a better progress indicator.
- if (progress >= pb->last_progress)
- ras->total_progress += (progress - pb->last_progress);
- else
- // Session total has been reset. A new stream started
- ras->total_progress += pb->last_progress;
- pb->last_progress = progress;
- ras->progress_func(ras->total_progress, -1, ras->progress_baton, pb->pool);
- }
- else
- {
- // Neon provides total bytes to receive information. Pass literally
- // to allow providing a percentage.
- ras->progress_func(progress, total, ras->progress_baton, pb->pool);
- }
- pb->last_progress_time = now;
- }
- }
- }
- static atomic_t neon_initialized = 0;
- static error_t
- initialize_neon(
- void * baton,
- apr_pool_t * scratch_pool)
- {
- if (ne_sock_init() != 0)
- return error_create(WEBDAV_ERR_DAV_SOCK_INIT, NULL,
- "Network socket initialization failed");
- return WEBDAV_NO_ERROR;
- }
- static error_t
- ensure_neon_initialized()
- {
- return atomic_init_once(&neon_initialized, initialize_neon, NULL, NULL);
- }
- static const char * const *
- ra_neon_get_schemes(apr_pool_t * pool)
- {
- static const char * schemes_no_ssl[] = { "http", NULL };
- static const char * schemes_ssl[] = { "http", "https", NULL };
- return ne_has_support(NE_FEATURE_SSL) ? schemes_ssl : schemes_no_ssl;
- }
- static error_t
- neon_open(
- session_t * session,
- const char ** corrected_url,
- const char * session_URL,
- const callbacks2_t * callbacks,
- void * callback_baton,
- apr_pool_t * pool)
- {
- assert(callback_baton);
- callback_baton_t * cb = static_cast<callback_baton_t *>(callback_baton);
- *corrected_url = NULL;
- ne_uri * uri = NULL;
- WEBDAV_ERR(parse_ne_uri(&uri, session_URL, pool));
- // Initialize neon if required
- WEBDAV_ERR(ensure_neon_initialized());
- int is_ssl_session = (strcmp(uri->scheme, "https") == 0);
- if (is_ssl_session)
- {
- if (ne_has_support(NE_FEATURE_SSL) == 0)
- return error_create(WEBDAV_ERR_DAV_SOCK_INIT, NULL,
- "TLS is not supported");
- }
- ne_session * sess = ne_session_create(uri->scheme, uri->host, uri->port);
- apr_pool_cleanup_register(pool, sess, cleanup_session, apr_pool_cleanup_null);
- bool compression = FALSE;
- unsigned int neon_auth_types = 0;
- const char * pkcs11_provider = NULL;
- const char * ssl_authority_file = NULL;
- {
- int proxy_method = 0;
- const char * proxy_host = NULL;
- unsigned int proxy_port = 0;
- const char * proxy_username = NULL;
- const char * proxy_password = NULL;
- int timeout = 0;
- int debug = 0;
- const char * neon_debug_file_name = NULL;
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- WEBDAV_ERR(fs->GetServerSettings(
- &proxy_method,
- &proxy_host,
- &proxy_port,
- &proxy_username,
- &proxy_password,
- &timeout,
- &debug,
- &neon_debug_file_name,
- &compression,
- &pkcs11_provider,
- &ssl_authority_file,
- pool));
- if (neon_auth_types == 0)
- {
- // If there were no auth types specified in the configuration
- // file, provide the appropriate defaults.
- neon_auth_types = NE_AUTH_BASIC | NE_AUTH_DIGEST;
- if (is_ssl_session)
- neon_auth_types |= NE_AUTH_NEGOTIATE;
- }
- if (debug && neon_debug_file_name)
- {
- #ifdef NETBOX_DEBUG
- debug_file_baton_t * baton = static_cast<debug_file_baton_t *>(apr_pcalloc(pool, sizeof(*baton)));
- neon_debug_file_name = apr_pstrcat(pool, neon_debug_file_name, ".neondebug.log", NULL);
- baton->file = _fsopen(neon_debug_file_name, "w", SH_DENYWR);
- if (baton->file)
- {
- debug = NE_DBG_HTTP |
- // NE_DBG_XML | NE_DBG_HTTPAUTH |
- NE_DBG_HTTPPLAIN |
- // NE_DBG_XMLPARSE |
- NE_DBG_HTTPBODY |
- // NE_DBG_SSL |
- NE_DBG_FLUSH;
- ne_debug_init(baton->file, debug);
- }
- apr_pool_cleanup_register(pool, baton,
- cleanup_neon_debug_file,
- apr_pool_cleanup_null);
- #else
- ne_debug_init(NULL, 0);
- #endif // #ifdef NETBOX_DEBUG
- }
- TProxyMethod method = (TProxyMethod)proxy_method;
- if (method != ::pmNone)
- {
- if ((method == pmSocks4) || (method == pmSocks5))
- {
- enum ne_sock_sversion vers = method == pmSocks4 ? NE_SOCK_SOCKSV4A : NE_SOCK_SOCKSV5;
- ne_session_socks_proxy(sess, vers, proxy_host, proxy_port, proxy_username, proxy_password);
- }
- else if (proxy_host)
- {
- ne_session_proxy(sess, proxy_host, proxy_port);
- if (proxy_username)
- {
- proxy_auth_baton_t * pab = static_cast<proxy_auth_baton_t *>(apr_pcalloc(pool, sizeof(*pab)));
- pab->username = proxy_username;
- pab->password = proxy_password ? proxy_password : "";
- ne_set_proxy_auth(sess, proxy_auth, pab);
- }
- else
- {
- // Enable (only) the Negotiate scheme for proxy
- // authentication, if no username/password is
- // configured.
- ne_add_proxy_auth(sess, NE_AUTH_NEGOTIATE, NULL, NULL);
- }
- }
- }
- if (!timeout)
- timeout = DEFAULT_HTTP_TIMEOUT;
- ne_set_read_timeout(sess, timeout);
- ne_set_connect_timeout(sess, timeout);
- }
- {
- static std::string useragent = "WinSCP";
- ne_set_useragent(sess, useragent.c_str());
- }
- // Create and fill a session_baton.
- neon_session_t * ras = static_cast<neon_session_t *>(apr_pcalloc(pool, sizeof(*ras)));
- ras->pool = pool;
- {
- // canonicalize url
- const char * remote_url = urlpath_canonicalize(session_URL, pool);
- ras->url = stringbuf_create(remote_url, pool);
- }
- // copies uri pointer members, they get free'd in __close.
- ras->root = *uri;
- ras->ne_sess = sess;
- ras->callbacks = callbacks;
- ras->callback_baton = callback_baton;
- ras->compression = compression;
- ras->progress_baton = callbacks->progress_baton;
- ras->progress_func = callbacks->progress_func;
- ras->capabilities = apr_hash_make(ras->pool);
- // note that ras->username and ras->password are still NULL at this point.
- // Register an authentication 'pull' callback with the neon sessions
- ne_add_server_auth(sess, neon_auth_types, request_auth, ras);
- if (is_ssl_session)
- {
- bool trust_default_ca = false;
- // PEM-encoded Certificate Authority (CA) SSL certificate
- const char * authorities = ssl_authority_file;
- if (authorities != NULL && *authorities)
- {
- const char * file = authorities;
- ne_ssl_certificate * ca_cert = NULL;
- ca_cert = ne_ssl_cert_read(file);
- if (ca_cert == NULL)
- {
- return error_createf(
- WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Invalid config: unable to load certificate file '%s'", file);
- }
- ne_ssl_trust_cert(sess, ca_cert);
- ne_ssl_cert_free(ca_cert);
- ca_cert = NULL;
- }
- // When the CA certificate or server certificate has
- // verification problems, neon will call our verify function before
- // outright rejection of the connection.*/
- ne_ssl_set_verify(sess, server_ssl_callback, ras);
- // For client connections, we register a callback for if the server
- // wants to authenticate the client via client certificate.
- if (pkcs11_provider && *pkcs11_provider)
- {
- ne_ssl_pkcs11_provider * provider;
- int rv;
- // Initialize the PKCS#11 provider.
- rv = ne_ssl_pkcs11_provider_init(&provider, pkcs11_provider);
- if (rv != NE_PK11_OK)
- {
- return error_createf(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Invalid config: unable to load PKCS#11 provider '%s'",
- pkcs11_provider);
- }
- // Share the provider between the two sessions.
- ne_ssl_set_pkcs11_provider(sess, provider);
- ne_ssl_pkcs11_provider_pin(provider, client_ssl_pkcs11_pin_entry, ras);
- apr_pool_cleanup_register(pool, provider, cleanup_p11provider,
- apr_pool_cleanup_null);
- }
- // Note the "else"; if a PKCS#11 provider is set up, a client
- // cert callback is already configured, so don't displace it
- // with the normal one here.
- else
- {
- ne_ssl_provide_clicert(sess, client_ssl_callback, ras);
- }
- // See if the user wants us to trust "default" openssl CAs.
- // TODO: option "trust default CA"
- trust_default_ca = true;
- if (trust_default_ca)
- {
- ne_ssl_trust_default_ca(sess);
- }
- }
- if (ras->progress_func)
- {
- neonprogress_baton_t * progress1 = static_cast<neonprogress_baton_t *>(apr_pcalloc(pool, sizeof(*progress1)));
- neonprogress_baton_t * progress2 = static_cast<neonprogress_baton_t *>(apr_pcalloc(pool, sizeof(*progress2)));
- progress1->pool = pool;
- progress1->ras = ras;
- progress1->last_progress = 0;
- progress2->pool = pool;
- progress2->ras = ras;
- progress2->last_progress = 0;
- ne_set_progress(sess, ra_neon_neonprogress, progress1);
- }
- session->priv = ras;
- const char * corrected = NULL;
- error_t err = neon_exchange_capabilities(ras, &corrected, pool);
- if (corrected)
- *corrected_url = corrected;
- return err;
- }
- static error_t
- neon_reparent(
- session_t * session,
- const char * url,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- ne_uri * uri = NULL;
- WEBDAV_ERR(parse_ne_uri(&uri, url, session->pool));
- ras->root = *uri;
- stringbuf_set(ras->url, url);
- ras->webdav_root = neon_uri_unparse(uri, session->pool);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_get_session_url(
- session_t * session,
- const char ** url,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- *url = apr_pstrmemdup(pool, ras->url->data, ras->url->len);
- return WEBDAV_NO_ERROR;
- }
- static const ne_propname restype_props[] =
- {
- { "DAV:", "resourcetype" },
- { NULL }
- };
- static error_t
- neon_get_file(
- session_t * session,
- const char * path,
- stream_t * stream,
- apr_hash_t ** props,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- const char * url = path_url_add_component2(ras->url->data, path, pool);
- const ne_propname * which_props = NULL;
- const char * final_url = url;
- if (props)
- {
- // Request all properties if caller requested them.
- which_props = starting_props;
- }
- else
- {
- // Request only resource type on other cases.
- which_props = restype_props;
- }
- neon_resource_t * rsrc = NULL;
- WEBDAV_ERR(neon_get_props_resource(&rsrc, ras, final_url,
- which_props,
- false,
- pool));
- if (rsrc->is_collection)
- {
- return error_create(WEBDAV_ERR_FS_NOT_FILE, NULL,
- "Can't get text contents of a directory");
- }
- if (stream)
- {
- file_write_ctx_t fwc = {0};
- fwc.stream = stream;
- // Fetch the file, shoving it at the provided stream.
- WEBDAV_ERR(custom_get_request(ras, final_url, path,
- get_file_reader, &fwc,
- ras->callback_baton,
- pool));
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_get_dir(
- session_t * session,
- apr_hash_t ** dirents,
- const char * path,
- apr_uint32_t dirent_fields,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- const char * url = path_url_add_component2(ras->url->data, path, pool);
- const char * final_url = url;
- if (dirents)
- {
- // Just like Nautilus, Cadaver, or any other browser, we do a
- // PROPFIND on the directory of depth 1.
- apr_hash_t * resources = NULL;
- WEBDAV_ERR(neon_get_props(&resources, ras,
- final_url, NEON_DEPTH_ONE,
- starting_props,
- false,
- pool));
- // Count the number of path components in final_url.
- apr_size_t final_url_n_components = path_component_count(final_url);
- // Now we have a hash that maps a bunch of url children to resource
- // objects. Each resource object contains the properties of the
- // child. Parse these resources into dirent_t structs.
- *dirents = apr_hash_make(pool);
- for (apr_hash_index_t * hi = apr_hash_first(pool, resources); hi;
- hi = apr_hash_next(hi))
- {
- const void * key = NULL;
- void * val = NULL;
- const char * childname = NULL;
- neon_resource_t * resource = NULL;
- const string_t * propval = NULL;
- dirent_t * entry = NULL;
- apr_hash_this(hi, &key, NULL, &val);
- childname = relpath_canonicalize(static_cast<const char *>(key), pool);
- resource = static_cast<neon_resource_t *>(val);
- // Skip the effective '.' entry that comes back from
- // NEON_DEPTH_ONE. The children must have one more
- // component then final_url.
- // Note that we can't just strcmp the URLs because of URL encoding
- // differences (i.e. %3c vs. %3C etc.)
- if (path_component_count(childname) < final_url_n_components - 1)
- continue;
- entry = static_cast<dirent_t *>(apr_pcalloc(pool, sizeof(*entry)));
- if (dirent_fields & WEBDAV_DIRENT_KIND)
- {
- // node kind
- entry->kind = resource->is_collection ? node_dir : node_file;
- }
- if (dirent_fields & WEBDAV_DIRENT_SIZE)
- {
- // size
- propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
- NEON_PROP_GETCONTENTLENGTH,
- APR_HASH_KEY_STRING));
- if (propval == NULL)
- entry->size = 0;
- else
- entry->size = atoui64(propval->data);
- }
- if (dirent_fields & WEBDAV_DIRENT_TIME)
- {
- propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
- NEON_PROP_CREATIONDATE,
- APR_HASH_KEY_STRING));
- if (propval != NULL)
- WEBDAV_ERR(time_from_cstring(&(entry->time),
- propval->data, pool));
- }
- apr_hash_set(*dirents,
- path_uri_decode(relpath_basename(childname,
- pool),
- pool),
- APR_HASH_KEY_STRING, entry);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_check_path(
- session_t * session,
- const char * path,
- node_kind_t * kind,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- const char * url = ras->url->data;
- error_t err = 0;
- bool is_dir = FALSE;
- // If we were given a relative path to append, append it.
- if (path)
- url = path_url_add_component2(url, path, pool);
- if (!err)
- {
- neon_resource_t * rsrc;
- const char * full_bc_url = url;
- // query the DAV:resourcetype of the full, assembled URL.
- err = neon_get_starting_props(&rsrc, ras, full_bc_url, true, pool);
- if (!err)
- is_dir = rsrc->is_collection != 0;
- }
- if (err == WEBDAV_NO_ERROR)
- {
- if (is_dir)
- *kind = node_dir;
- else
- *kind = node_file;
- }
- else if (err == WEBDAV_ERR_FS_NOT_FOUND)
- {
- error_clear(&err);
- err = WEBDAV_NO_ERROR;
- *kind = node_none;
- }
- return err;
- }
- static error_t
- neon_stat(
- session_t * session,
- const char * path,
- dirent_t ** dirent,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- const char * url = ras->url->data;
- // If we were given a relative path to append, append it.
- if (path)
- url = path_url_add_component2(url, path, pool);
- const char * final_url = url;
- // Depth-zero PROPFIND is the One True DAV Way.
- apr_hash_t * resources = NULL;
- error_t err = neon_get_props(&resources, ras, final_url,
- NEON_DEPTH_ZERO,
- starting_props,
- false,
- pool);
- if (err)
- {
- if (err == WEBDAV_ERR_FS_NOT_FOUND)
- {
- // easy out:
- error_clear(&err);
- *dirent = NULL;
- return WEBDAV_NO_ERROR;
- }
- else
- return err;
- }
- // Copying parsing code from neon_get_dir() here. The hash
- // of resources only contains one item, but there's no other way to
- // get the item.
- for (apr_hash_index_t * hi = apr_hash_first(pool, resources); hi;
- hi = apr_hash_next(hi))
- {
- void * val = NULL;
- apr_hash_this(hi, NULL, NULL, &val);
- neon_resource_t * resource = static_cast<neon_resource_t *>(val);
- dirent_t * entry = static_cast<dirent_t *>(apr_pcalloc(pool, sizeof(*entry)));
- entry->kind = resource->is_collection ? node_dir : node_file;
- const string_t * propval = NULL;
- // entry->size is already 0 by virtue of pcalloc().
- if (entry->kind == node_file)
- {
- propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
- NEON_PROP_GETCONTENTLENGTH,
- APR_HASH_KEY_STRING));
- if (propval)
- entry->size = atoui64(propval->data);
- }
- propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
- NEON_PROP_CREATIONDATE,
- APR_HASH_KEY_STRING));
- if (propval != NULL)
- WEBDAV_ERR(time_from_cstring(&(entry->time),
- propval->data, pool));
- *dirent = entry;
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_get_webdav_resource_root(
- session_t * session,
- const char ** url,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- *url = ras->webdav_root;
- return WEBDAV_NO_ERROR;
- }
- static const vtable_t neon_vtable =
- {
- NULL, // get_description
- ra_neon_get_schemes, // get_schemes
- neon_open, // open_session
- neon_reparent, // reparent
- neon_get_session_url, // get_session_url
- neon_get_file, // get_file
- neon_get_dir, // get_dir
- neon_check_path, // check_path
- neon_stat, // stat
- neon_get_webdav_resource_root, // get_webdav_resource_root
- };
- static error_t
- neon_init(
- const vtable_t ** vtable,
- apr_pool_t * pool)
- {
- *vtable = &neon_vtable;
- return WEBDAV_NO_ERROR;
- }
- } // namespace webdav
- //---------------------------------------------------------------------------
- class TSessionData;
- //---------------------------------------------------------------------------
- class TWebDAVFileListHelper
- {
- public:
- explicit TWebDAVFileListHelper(TWebDAVFileSystem * FileSystem, TRemoteFileList * FileList,
- bool IgnoreFileList) :
- FFileSystem(FileSystem),
- FFileList(FFileSystem->FFileList),
- FIgnoreFileList(FFileSystem->FIgnoreFileList)
- {
- FFileSystem->FFileList = FileList;
- FFileSystem->FIgnoreFileList = IgnoreFileList;
- }
- ~TWebDAVFileListHelper()
- {
- FFileSystem->FFileList = FFileList;
- FFileSystem->FIgnoreFileList = FIgnoreFileList;
- }
- private:
- TWebDAVFileSystem * FFileSystem;
- TRemoteFileList * FFileList;
- bool FIgnoreFileList;
- };
- //---------------------------------------------------------------------------
- #undef FILE_OPERATION_LOOP_EX
- #define FILE_OPERATION_LOOP_EX(ALLOW_SKIP, MESSAGE, OPERATION) \
- FILE_OPERATION_LOOP_CUSTOM(FTerminal, ALLOW_SKIP, MESSAGE, OPERATION, L"")
- //---------------------------------------------------------------------------
- static const UnicodeString CONST_WEBDAV_PROTOCOL_BASE_NAME = L"WebDAV";
- //===========================================================================
- TWebDAVFileSystem::TWebDAVFileSystem(TTerminal * ATerminal) :
- TCustomFileSystem(ATerminal),
- FFileList(NULL),
- FOnCaptureOutput(NULL),
- FPasswordFailed(false),
- FActive(false),
- FFileTransferAbort(ftaNone),
- FIgnoreFileList(false),
- FFileTransferCancelled(false),
- FFileTransferResumed(0),
- FFileTransferPreserveTime(false),
- FHasTrailingSlash(false),
- FFileTransferCPSLimit(0),
- FLastReadDirectoryProgress(0),
- FCurrentOperationProgress(NULL),
- FTransferStatusCriticalSection(new TCriticalSection()),
- webdav_pool(NULL),
- FSession(NULL)
- {
- FFileSystemInfo.ProtocolBaseName = CONST_WEBDAV_PROTOCOL_BASE_NAME;
- FFileSystemInfo.ProtocolName = FFileSystemInfo.ProtocolBaseName;
- if (apr_initialize() != APR_SUCCESS)
- throw ExtException(UnicodeString(L"Cannot init APR"), NULL);
- apr_pool_create(&webdav_pool, NULL);
- }
- //---------------------------------------------------------------------------
- __fastcall TWebDAVFileSystem::~TWebDAVFileSystem()
- {
- delete FTransferStatusCriticalSection;
- FTransferStatusCriticalSection = NULL;
- webdav_pool_destroy(webdav_pool);
- apr_terminate();
- webdav_pool = NULL;
- ne_sock_exit();
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Open()
- {
- FCurrentDirectory = L"";
- FHasTrailingSlash = false;
- TSessionData * Data = FTerminal->SessionData;
- FSessionInfo.LoginTime = Now();
- bool Ssl = (FTerminal->SessionData->Ftps != ftpsNone);
- if (Ssl)
- {
- FSessionInfo.SecurityProtocolName = LoadStr(FTPS_IMPLICIT);
- }
- UnicodeString HostName = Data->HostNameExpanded;
- size_t Port = Data->PortNumber;
- UnicodeString ProtocolName = !Ssl ? L"http" : L"https";
- UnicodeString UserName = Data->UserNameExpanded;
- UnicodeString Path = Data->RemoteDirectory;
- UnicodeString Url = FORMAT(L"%s://%s:%d%s", (ProtocolName.c_str(), HostName.c_str(), Port, Path.c_str()));
- FPasswordFailed = false;
- FTerminal->Information(LoadStr(STATUS_CONNECT), true);
- for (int I = 0; I < 5; I++)
- {
- FActive = false;
- try
- {
- FActive = (WEBDAV_NO_ERROR == OpenURL(Url, webdav_pool));
- if (FActive)
- {
- break;
- }
- }
- catch (...)
- {
- if (FFileTransferCancelled)
- break;
- apr_sleep(200000); // 0.2 sec
- }
- }
- if (!FActive)
- {
- FTerminal->Closed();
- throw Exception(LoadStr(CONNECTION_FAILED));
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Close()
- {
- assert(FActive);
- FTerminal->Closed();
- FActive = false;
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::GetActive()
- {
- return FActive;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CollectUsage()
- {
- }
- //---------------------------------------------------------------------------
- const TSessionInfo & __fastcall TWebDAVFileSystem::GetSessionInfo()
- {
- return FSessionInfo;
- }
- //---------------------------------------------------------------------------
- const TFileSystemInfo & __fastcall TWebDAVFileSystem::GetFileSystemInfo(bool Retrieve)
- {
- return FFileSystemInfo;
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::TemporaryTransferFile(const UnicodeString & /*FileName*/)
- {
- return false;
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::GetStoredCredentialsTried()
- {
- return false;
- }
- //---------------------------------------------------------------------------
- UnicodeString __fastcall TWebDAVFileSystem::GetUserName()
- {
- return FUserName;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Idle()
- {
- // TODO: Keep session alive
- return;
- }
- //---------------------------------------------------------------------------
- UnicodeString __fastcall TWebDAVFileSystem::AbsolutePath(const UnicodeString Path, bool /*Local*/)
- {
- return ::AbsolutePath(GetCurrentDirectory(), Path);
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::IsCapable(int Capability) const
- {
- assert(FTerminal);
- switch (Capability)
- {
- case fcUserGroupListing:
- case fcModeChanging:
- case fcModeChangingUpload:
- case fcPreservingTimestampUpload:
- case fcGroupChanging:
- case fcOwnerChanging:
- case fcAnyCommand:
- case fcShellAnyCommand:
- case fcHardLink:
- case fcSymbolicLink:
- case fcResolveSymlink:
- return false;
- case fcRename:
- case fcRemoteMove:
- case fcRemoteCopy:
- return true;
- case fcTextMode:
- case fcNativeTextMode:
- case fcNewerOnlyUpload:
- case fcTimestampChanging:
- case fcLoadingAdditionalProperties:
- case fcCheckingSpaceAvailable:
- case fcIgnorePermErrors:
- case fcCalculatingChecksum:
- case fcSecondaryShell: // has fcShellAnyCommand
- case fcGroupOwnerChangingByID: // by name
- case fcRemoveCtrlZUpload:
- case fcRemoveBOMUpload:
- return false;
- default:
- assert(false);
- return false;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::EnsureLocation()
- {
- if (!FCachedDirectoryChange.IsEmpty())
- {
- FTerminal->LogEvent(FORMAT(L"Locating to cached directory \"%s\".",
- (FCachedDirectoryChange.c_str())));
- UnicodeString Directory = FCachedDirectoryChange;
- FCachedDirectoryChange = L"";
- try
- {
- ChangeDirectory(Directory);
- }
- catch (...)
- {
- // when location to cached directory fails, pretend again
- // location in cached directory
- // here used to be check (CurrentDirectory != Directory), but it is
- // false always (currentdirectory is already set to cached directory),
- // making the condition below useless. check removed.
- if (FTerminal->GetActive())
- {
- FCachedDirectoryChange = Directory;
- }
- throw;
- }
- }
- }
- //---------------------------------------------------------------------------
- UnicodeString __fastcall TWebDAVFileSystem::GetCurrentDirectory()
- {
- return FCurrentDirectory;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::DoStartup()
- {
- FTerminal->SetExceptionOnFail(true);
- // retrieve initialize working directory to save it as home directory
- ReadCurrentDirectory();
- FTerminal->SetExceptionOnFail(false);
- }
- //---------------------------------------------------------------------------
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::LookupUsersGroups()
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadCurrentDirectory()
- {
- if (FCachedDirectoryChange.IsEmpty())
- {
- FCurrentDirectory = FCurrentDirectory.IsEmpty() ? UnicodeString(L"/") : FCurrentDirectory;
- }
- else
- {
- FCurrentDirectory = FCachedDirectoryChange;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::HomeDirectory()
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::AnnounceFileListOperation()
- {
- // noop
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::DoChangeDirectory(const UnicodeString Directory)
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ChangeDirectory(const UnicodeString ADirectory)
- {
- UnicodeString Directory = ADirectory;
- bool HasTrailingSlash = (Directory.Length() > 0) && (Directory[Directory.Length()] == L'/');
- try
- {
- // For changing directory, we do not make paths absolute, instead we
- // delegate this to the server, hence we synchronize current working
- // directory with the server and only then we ask for the change with
- // relative path.
- // But if synchronization fails, typically because current working directory
- // no longer exists, we fall back to out own resolution, to give
- // user chance to leave the non-existing directory.
- EnsureLocation();
- }
- catch (...)
- {
- if (FTerminal->GetActive())
- {
- Directory = AbsolutePath(Directory, false);
- if (HasTrailingSlash)
- Directory = ::UnixIncludeTrailingBackslash(Directory);
- }
- else
- {
- throw;
- }
- }
- FCurrentDirectory = AbsolutePath(Directory, false);
- if (HasTrailingSlash)
- FCurrentDirectory = ::UnixIncludeTrailingBackslash(FCurrentDirectory);
- // make next ReadCurrentDirectory retrieve actual server-side current directory
- FCachedDirectoryChange = L"";
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CachedChangeDirectory(const UnicodeString Directory)
- {
- FCachedDirectoryChange = UnixExcludeTrailingBackslash(Directory);
- }
- void __fastcall TWebDAVFileSystem::DoReadDirectory(TRemoteFileList * FileList)
- {
- FileList->Reset();
- // add parent directory
- FileList->AddFile(new TRemoteParentDirectory(FTerminal));
- FLastReadDirectoryProgress = 0;
- TWebDAVFileListHelper Helper(this, FileList, false);
- // always specify path to list, do not attempt to
- // list "current" dir as:
- // 1) List() lists again the last listed directory, not the current working directory
- // 2) we handle this way the cached directory change
- UnicodeString Directory = AbsolutePath(FileList->Directory, false);
- if (FHasTrailingSlash)
- Directory = ::UnixIncludeTrailingBackslash(Directory);
- WebDAVGetList(Directory);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadDirectory(TRemoteFileList * FileList)
- {
- assert(FileList);
- bool Repeat = false;
- do
- {
- Repeat = false;
- try
- {
- DoReadDirectory(FileList);
- }
- catch (Exception &)
- {
- if (!FTerminal->GetActive())
- {
- FTerminal->Reopen(ropNoReadDirectory);
- Repeat = true;
- }
- else
- {
- throw;
- }
- }
- }
- while (Repeat);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadSymlink(TRemoteFile * SymlinkFile,
- TRemoteFile *& File)
- {
- CustomReadFile(SymlinkFile->LinkTo, File, SymlinkFile);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadFile(const UnicodeString FileName,
- TRemoteFile *& File)
- {
- CustomReadFile(FileName, File, NULL);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CustomReadFile(const UnicodeString FileName,
- TRemoteFile *& File, TRemoteFile * ALinkedByFile)
- {
- File = NULL;
- bool isExist = false;
- int is_dir = 0;
- isExist = WebDAVCheckExisting(FileName.c_str(), is_dir);
- if (isExist)
- {
- File = new TRemoteFile();
- if (is_dir)
- File->Type = FILETYPE_DIRECTORY;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::DeleteFile(const UnicodeString FileName,
- const TRemoteFile * File, int Params, TRmSessionAction & Action)
- {
- USEDPARAM(File);
- USEDPARAM(Params);
- UnicodeString FullFileName = File->FullFileName;
- bool res = WebDAVDeleteFile(FullFileName.c_str());
- if (!res)
- {
- THROW_SKIP_FILE(NULL, L"");
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::RenameFile(const UnicodeString FileName,
- const UnicodeString NewName)
- {
- UnicodeString FullFileName = ::UnixIncludeTrailingBackslash(FCurrentDirectory) + FileName;
- bool res = WebDAVRenameFile(FullFileName.c_str(), NewName.c_str());
- if (!res)
- {
- THROW_SKIP_FILE(NULL, L"");
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CopyFile(const UnicodeString FileName,
- const UnicodeString NewName)
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CreateDirectory(const UnicodeString DirName)
- {
- UnicodeString FullDirName = AbsolutePath(DirName, true);
- bool res = WebDAVMakeDirectory(FullDirName.c_str());
- if (!res)
- {
- TStringList * Strings = new TStringList();
- Strings->Delimiter = L'/';
- Strings->DelimitedText = DirName;
- UnicodeString CurDir;
- for (int i = 0; i < Strings->Count; i++)
- {
- if (Strings->Strings[i].IsEmpty())
- {
- continue;
- }
- CurDir += L"/" + Strings->Strings[i];
- res = WebDAVMakeDirectory(CurDir.c_str());
- }
- if (!res)
- {
- THROW_SKIP_FILE(NULL, L"");
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CreateLink(const UnicodeString FileName,
- const UnicodeString PointTo, bool Symbolic)
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ChangeFileProperties(const UnicodeString FileName,
- const TRemoteFile * File, const TRemoteProperties * Properties,
- TChmodSessionAction & Action)
- {
- assert(Properties);
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::LoadFilesProperties(TStrings * /*FileList*/)
- {
- assert(false);
- return false;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CalculateFilesChecksum(const UnicodeString & /*Alg*/,
- TStrings * /*FileList*/, TStrings * /*Checksums*/,
- TCalculatedChecksumEvent /*OnCalculatedChecksum*/)
- {
- assert(false);
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::ConfirmOverwrite(UnicodeString & FileName,
- TOverwriteMode & OverwriteMode, TFileOperationProgressType * OperationProgress,
- const TOverwriteFileParams * FileParams, const TCopyParamType * CopyParam,
- int Params, bool AutoResume, unsigned int &Answer)
- {
- bool Result;
- bool CanAutoResume = FLAGSET(Params, cpNoConfirmation) && AutoResume;
- bool CanResume = false; // disable resume
- Answer = 0;
- if (CanAutoResume && CanResume)
- {
- Answer = qaRetry;
- }
- else
- {
- // retry = "resume"
- // all = "yes to newer"
- // ignore = "rename"
- int Answers = qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll | qaAll | qaIgnore;
- if (CanResume)
- {
- Answers |= qaRetry;
- }
- TQueryButtonAlias Aliases[3];
- Aliases[0].Button = qaRetry;
- Aliases[0].Alias = LoadStr(RESUME_BUTTON);
- Aliases[1].Button = qaAll;
- Aliases[1].Alias = LoadStr(YES_TO_NEWER_BUTTON);
- Aliases[2].Button = qaIgnore;
- Aliases[2].Alias = LoadStr(RENAME_BUTTON);
- TQueryParams QueryParams(qpNeverAskAgainCheck);
- QueryParams.Aliases = Aliases;
- QueryParams.AliasesCount = LENOF(Aliases);
- SUSPEND_OPERATION (
- Answer = FTerminal->ConfirmFileOverwrite(FileName, FileParams,
- Answers, &QueryParams,
- OperationProgress->Side == osLocal ? osRemote : osLocal,
- CopyParam, Params, OperationProgress);
- )
- }
- Result = true;
- switch (Answer)
- {
- // resume
- case qaRetry:
- OverwriteMode = omResume;
- assert(FileParams != NULL);
- assert(CanResume);
- FFileTransferResumed = FileParams->DestSize;
- break;
- // rename
- case qaIgnore:
- if (FTerminal->PromptUser(FTerminal->SessionData, pkFileName,
- LoadStr(RENAME_TITLE), L"", LoadStr(RENAME_PROMPT2), true, 0, FileName))
- {
- OverwriteMode = omOverwrite;
- }
- else
- {
- if (!OperationProgress->Cancel)
- {
- OperationProgress->Cancel = csCancel;
- }
- FFileTransferAbort = ftaCancel;
- Result = false;
- }
- break;
- case qaYes:
- OverwriteMode = omOverwrite;
- break;
- case qaNo:
- FFileTransferAbort = ftaSkip;
- Result = false;
- break;
- case qaCancel:
- if (!OperationProgress->Cancel)
- {
- OperationProgress->Cancel = csCancel;
- }
- FFileTransferAbort = ftaCancel;
- Result = false;
- break;
- default:
- assert(false);
- Result = false;
- break;
- }
- return Result;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CustomCommandOnFile(const UnicodeString FileName,
- const TRemoteFile * File, UnicodeString Command, int Params, TCaptureOutputEvent OutputEvent)
- {
- assert(File);
- bool Dir = File->IsDirectory && !File->IsSymLink;
- if (Dir && (Params & ccRecursive))
- {
- TCustomCommandParams AParams;
- AParams.Command = Command;
- AParams.Params = Params;
- AParams.OutputEvent = OutputEvent;
- FTerminal->ProcessDirectory(FileName, FTerminal->CustomCommandOnFile, &AParams);
- }
- if (!Dir || (Params & ccApplyToDirectories))
- {
- TCustomCommandData Data(FTerminal);
- UnicodeString Cmd = TRemoteCustomCommand(
- Data, FTerminal->GetCurrentDirectory(), FileName, L"").
- Complete(Command, true);
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::AnyCommand(const UnicodeString Command,
- TCaptureOutputEvent OutputEvent)
- {
- }
- //---------------------------------------------------------------------------
- UnicodeString __fastcall TWebDAVFileSystem::FileUrl(const UnicodeString FileName)
- {
- return FTerminal->FileUrl(FTerminal->SessionData->Ftps == ftpsNone ?
- L"http" : L"https", FileName);
- }
- //---------------------------------------------------------------------------
- TStrings * __fastcall TWebDAVFileSystem::GetFixedPaths()
- {
- return NULL;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::SpaceAvailable(const UnicodeString Path,
- TSpaceAvailable & /*ASpaceAvailable*/)
- {
- assert(false);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CopyToRemote(TStrings * FilesToCopy,
- const UnicodeString ATargetDir, const TCopyParamType * CopyParam,
- int Params, TFileOperationProgressType * OperationProgress,
- TOnceDoneOperation & OnceDoneOperation)
- {
- assert((FilesToCopy != NULL) && (OperationProgress != NULL));
- Params &= ~cpAppend;
- UnicodeString FileName, FileNameOnly;
- UnicodeString TargetDir = AbsolutePath(ATargetDir, false);
- UnicodeString FullTargetDir = ::UnixIncludeTrailingBackslash(TargetDir);
- intptr_t Index = 0;
- while ((Index < FilesToCopy->Count) && !OperationProgress->Cancel)
- {
- bool Success = false;
- FileName = FilesToCopy->Strings[Index];
- FileNameOnly = ExtractFileName(FileName, false);
- try
- {
- try
- {
- if (FTerminal->SessionData->CacheDirectories)
- {
- FTerminal->DirectoryModified(TargetDir, false);
- if (::DirectoryExists(::ExtractFilePath(FileName)))
- {
- FTerminal->DirectoryModified(FullTargetDir + FileNameOnly, true);
- }
- }
- WebDAVSourceRobust(FileName, FullTargetDir, CopyParam, Params, OperationProgress,
- tfFirstLevel);
- Success = true;
- }
- catch (EScpSkipFile & E)
- {
- SUSPEND_OPERATION (
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- }
- }
- __finally
- {
- OperationProgress->Finish(FileName, Success, OnceDoneOperation);
- }
- Index++;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::WebDAVSourceRobust(const UnicodeString FileName,
- const UnicodeString TargetDir, const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags)
- {
- bool Retry = false;
- TUploadSessionAction Action(FTerminal->ActionLog);
- do
- {
- Retry = false;
- try
- {
- WebDAVSource(FileName, TargetDir, CopyParam, Params, OperationProgress,
- Flags, Action);
- }
- catch (Exception & E)
- {
- Retry = true;
- if (FTerminal->GetActive() ||
- !FTerminal->QueryReopen(&E, ropNoReadDirectory, OperationProgress))
- {
- FTerminal->RollbackAction(Action, OperationProgress, &E);
- throw;
- }
- }
- if (Retry)
- {
- OperationProgress->RollbackTransfer();
- Action.Restart();
- // prevent overwrite confirmations
- // (should not be set for directories!)
- Params |= cpNoConfirmation;
- Flags |= tfAutoResume;
- }
- }
- while (Retry);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::WebDAVSource(const UnicodeString FileName,
- const UnicodeString TargetDir, const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags,
- TUploadSessionAction & Action)
- {
- bool CheckExistence = UnixComparePaths(TargetDir, FTerminal->GetCurrentDirectory()) &&
- (FTerminal->FFiles != NULL) && FTerminal->FFiles->Loaded;
- bool CanProceed = false;
- UnicodeString FileNameOnly =
- CopyParam->ChangeFileName(ExtractFileName(FileName, false), osLocal, true);
- if (CheckExistence)
- {
- TRemoteFile * File = FTerminal->FFiles->FindFile(FileNameOnly);
- if (File != NULL)
- {
- unsigned int Answer = 0;
- if (File->IsDirectory)
- {
- UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
- TQueryParams QueryParams(qpNeverAskAgainCheck);
- SUSPEND_OPERATION (
- Answer = FTerminal->ConfirmFileOverwrite(
- FileNameOnly /*not used*/, NULL,
- qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
- &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
- );
- switch (Answer)
- {
- case qaYes:
- CanProceed = true;
- break;
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- break;
- default:
- break;
- }
- }
- else
- {
- __int64 Size;
- __int64 MTime;
- TOverwriteFileParams FileParams;
- FTerminal->OpenLocalFile(FileName, GENERIC_READ,
- NULL, NULL, NULL, &MTime, NULL,
- &Size);
- FileParams.SourceSize = Size;
- FileParams.SourceTimestamp = UnixToDateTime(MTime,
- FTerminal->SessionData->DSTMode);
- FileParams.DestSize = File->Size;
- FileParams.DestTimestamp = File->Modification;
- TOverwriteMode OverwriteMode = omOverwrite;
- bool AutoResume = false;
- ConfirmOverwrite(FileNameOnly, OverwriteMode, OperationProgress,
- &FileParams, CopyParam, Params, AutoResume, Answer);
- switch (Answer)
- {
- case qaYes:
- CanProceed = true;
- break;
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- break;
- default:
- break;
- }
- }
- }
- else
- {
- CanProceed = true;
- }
- }
- else
- {
- CanProceed = true;
- }
- if (CanProceed)
- {
- Action.FileName(ExpandUNCFileName(FileName));
- OperationProgress->SetFile(FileName, false);
- if (!FTerminal->AllowLocalFileTransfer(FileName, CopyParam))
- {
- FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
- THROW_SKIP_FILE_NULL;
- }
- __int64 Size;
- int Attrs;
- FTerminal->OpenLocalFile(FileName, GENERIC_READ, &Attrs,
- NULL, NULL, NULL, NULL, &Size);
- OperationProgress->SetFileInProgress();
- bool Dir = FLAGSET(Attrs, faDirectory);
- if (Dir)
- {
- Action.Cancel();
- WebDAVDirectorySource(IncludeTrailingBackslash(FileName), TargetDir,
- Attrs, CopyParam, Params, OperationProgress, Flags);
- }
- else
- {
- UnicodeString DestFileName = CopyParam->ChangeFileName(ExtractFileName(FileName, false),
- osLocal, FLAGSET(Flags, tfFirstLevel));
- FTerminal->LogEvent(FORMAT(L"Copying \"%s\" to remote directory started.", (FileName.c_str())));
- OperationProgress->SetLocalSize(Size);
- // Suppose same data size to transfer as to read
- // (not true with ASCII transfer)
- OperationProgress->SetTransferSize(OperationProgress->LocalSize);
- OperationProgress->TransferingFile = false;
- // Will we use ASCII of BINARY file transfer?
- TFileMasks::TParams MaskParams;
- MaskParams.Size = Size;
- ResetFileTransfer();
- TFileTransferData UserData;
- {
- unsigned int TransferType = 2;
- // ignore file list
- TWebDAVFileListHelper Helper(this, NULL, true);
- FFileTransferCPSLimit = OperationProgress->CPSLimit;
- // not used for uploads anyway
- FFileTransferPreserveTime = CopyParam->PreserveTime;
- // not used for uploads, but we get new name (if any) back in this field
- UserData.FileName = DestFileName;
- UserData.Params = Params;
- UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
- UserData.CopyParam = CopyParam;
- FileTransfer(FileName, FileName, DestFileName,
- TargetDir, false, Size, TransferType, UserData, OperationProgress);
- }
- UnicodeString DestFullName = TargetDir + UserData.FileName;
- // only now, we know the final destination
- Action.Destination(DestFullName);
- }
- // TODO : Delete also read-only files.
- if (FLAGSET(Params, cpDelete))
- {
- if (!Dir)
- {
- FILE_OPERATION_LOOP (FMTLOAD(DELETE_LOCAL_FILE_ERROR, (FileName.c_str())),
- THROWOSIFFALSE(::DeleteFile(FileName.c_str()));
- )
- }
- }
- else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (FileName.c_str())),
- THROWOSIFFALSE(FileSetAttr(FileName, Attrs & ~faArchive) == 0);
- )
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::WebDAVDirectorySource(const UnicodeString DirectoryName,
- const UnicodeString TargetDir, int Attrs, const TCopyParamType * CopyParam,
- int Params, TFileOperationProgressType * OperationProgress, unsigned int Flags)
- {
- UnicodeString DestDirectoryName = CopyParam->ChangeFileName(
- ExtractFileName(ExcludeTrailingBackslash(DirectoryName), false), osLocal,
- FLAGSET(Flags, tfFirstLevel));
- UnicodeString DestFullName = UnixIncludeTrailingBackslash(TargetDir + DestDirectoryName);
- // create DestFullName if it does not exist
- int IsDir = 0;
- bool Exists = WebDAVCheckExisting(DestFullName.c_str(), IsDir);
- if (!Exists)
- {
- CreateDirectory(DestFullName);
- }
- OperationProgress->SetFile(DirectoryName);
- WIN32_FIND_DATA SearchRec;
- bool FindOK = false;
- HANDLE findHandle = 0;
- FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
- UnicodeString path = DirectoryName + L"*.*";
- findHandle = FindFirstFile(path.c_str(), &SearchRec);
- FindOK = (findHandle != 0);
- if (!FindOK)
- {
- FindCheck(GetLastError());
- }
- );
- bool CreateDir = true;
- try
- {
- while (FindOK && !OperationProgress->Cancel)
- {
- UnicodeString FileName = DirectoryName + SearchRec.cFileName;
- try
- {
- if ((wcscmp(SearchRec.cFileName, THISDIRECTORY) != 0) && (wcscmp(SearchRec.cFileName, PARENTDIRECTORY) != 0))
- {
- WebDAVSourceRobust(FileName, DestFullName, CopyParam, Params, OperationProgress,
- Flags & ~(tfFirstLevel | tfAutoResume));
- // if any file got uploaded (i.e. there were any file in the
- // directory and at least one was not skipped),
- // do not try to create the directory,
- // as it should be already created by FZAPI during upload
- CreateDir = false;
- }
- }
- catch (EScpSkipFile & E)
- {
- // If ESkipFile occurs, just log it and continue with next file
- SUSPEND_OPERATION (
- // here a message to user was displayed, which was not appropriate
- // when user refused to overwrite the file in subdirectory.
- // hopefully it won't be missing in other situations.
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- }
- FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
- FindOK = (::FindNextFile(findHandle, &SearchRec) != 0);
- if (!FindOK)
- {
- FindCheck(GetLastError());
- }
- );
- }
- }
- __finally
- {
- ::FindClose(findHandle);
- }
- if (CreateDir)
- {
- TRemoteProperties Properties;
- if (CopyParam->PreserveRights)
- {
- Properties.Valid = TValidProperties() << vpRights;
- Properties.Rights = CopyParam->RemoteFileRights(Attrs);
- }
- try
- {
- FTerminal->SetExceptionOnFail(true);
- try
- {
- FTerminal->CreateDirectory(DestFullName, &Properties);
- }
- __finally
- {
- FTerminal->SetExceptionOnFail(false);
- }
- }
- catch (...)
- {
- TRemoteFile * File = NULL;
- // ignore non-fatal error when the directory already exists
- UnicodeString fn = UnixExcludeTrailingBackslash(DestFullName);
- if (fn.IsEmpty())
- {
- fn = L"/";
- }
- bool Rethrow =
- !FTerminal->GetActive() ||
- !FTerminal->FileExists(fn, &File) ||
- (File && !File->IsDirectory);
- delete File;
- if (Rethrow)
- {
- throw;
- }
- }
- }
- // TODO : Delete also read-only directories.
- // TODO : Show error message on failure.
- if (!OperationProgress->Cancel)
- {
- if (FLAGSET(Params, cpDelete))
- {
- RemoveDir(DirectoryName);
- }
- else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DirectoryName.c_str())),
- THROWOSIFFALSE(FileSetAttr(DirectoryName, Attrs & ~faArchive) == 0);
- )
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CopyToLocal(TStrings * FilesToCopy,
- const UnicodeString TargetDir, const TCopyParamType * CopyParam,
- int Params, TFileOperationProgressType * OperationProgress,
- TOnceDoneOperation & OnceDoneOperation)
- {
- Params &= ~cpAppend;
- UnicodeString FullTargetDir = ::IncludeTrailingBackslash(TargetDir);
- int Index = 0;
- while (Index < FilesToCopy->Count && !OperationProgress->Cancel)
- {
- UnicodeString FileName = FilesToCopy->Strings[Index];
- const TRemoteFile * File = dynamic_cast<const TRemoteFile *>(FilesToCopy->Objects[Index]);
- bool Success = false;
- FTerminal->SetExceptionOnFail(true);
- try
- {
- try
- {
- SinkRobust(AbsolutePath(FileName, false), File, FullTargetDir, CopyParam, Params,
- OperationProgress, tfFirstLevel);
- Success = true;
- }
- catch (EScpSkipFile & E)
- {
- SUSPEND_OPERATION (
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- }
- }
- __finally
- {
- OperationProgress->Finish(FileName, Success, OnceDoneOperation);
- FTerminal->SetExceptionOnFail(false);
- }
- Index++;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::SinkRobust(const UnicodeString FileName,
- const TRemoteFile * File, const UnicodeString TargetDir,
- const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags)
- {
- // the same in TSFTPFileSystem
- bool Retry;
- TDownloadSessionAction Action(FTerminal->ActionLog);
- do
- {
- Retry = false;
- try
- {
- Sink(FileName, File, TargetDir, CopyParam, Params, OperationProgress,
- Flags, Action);
- }
- catch (Exception & E)
- {
- Retry = true;
- if (FTerminal->GetActive() ||
- !FTerminal->QueryReopen(&E, ropNoReadDirectory, OperationProgress))
- {
- FTerminal->RollbackAction(Action, OperationProgress, &E);
- throw;
- }
- }
- if (Retry)
- {
- OperationProgress->RollbackTransfer();
- Action.Restart();
- assert(File != NULL);
- if (!File->IsDirectory)
- {
- // prevent overwrite confirmations
- Params |= cpNoConfirmation;
- Flags |= tfAutoResume;
- }
- }
- }
- while (Retry);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Sink(const UnicodeString FileName,
- const TRemoteFile * File, const UnicodeString TargetDir,
- const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags,
- TDownloadSessionAction & Action)
- {
- UnicodeString FileNameOnly = UnixExtractFileName(FileName);
- Action.FileName(FileName);
- assert(File);
- TFileMasks::TParams MaskParams;
- MaskParams.Size = File->Size;
- if (!CopyParam->AllowTransfer(FileName, osRemote, File->IsDirectory, MaskParams))
- {
- FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
- THROW_SKIP_FILE_NULL;
- }
- FTerminal->LogFileDetails(FileName, TDateTime(), File->Size);
- OperationProgress->SetFile(FileNameOnly);
- UnicodeString DestFileName = CopyParam->ChangeFileName(FileNameOnly,
- osRemote, FLAGSET(Flags, tfFirstLevel));
- UnicodeString DestFullName = TargetDir + DestFileName;
- if (File->IsDirectory)
- {
- bool CanProceed = true;
- if (::DirectoryExists(DestFullName))
- {
- unsigned int Answer = 0;
- UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
- TQueryParams QueryParams(qpNeverAskAgainCheck);
- SUSPEND_OPERATION (
- Answer = FTerminal->ConfirmFileOverwrite(
- FileNameOnly /*not used*/, NULL,
- qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
- &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
- );
- switch (Answer)
- {
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- default:
- break;
- }
- }
- if (CanProceed)
- {
- Action.Cancel();
- if (!File->IsSymLink)
- {
- FILE_OPERATION_LOOP (FMTLOAD(NOT_DIRECTORY_ERROR, (DestFullName.c_str())),
- int Attrs = FileGetAttr(DestFullName);
- if (FLAGCLEAR(Attrs, faDirectory)) { EXCEPTION; }
- );
- FILE_OPERATION_LOOP (FMTLOAD(CREATE_DIR_ERROR, (DestFullName.c_str())),
- THROWOSIFFALSE(ForceDirectories(DestFullName));
- );
- TSinkFileParams SinkFileParams;
- SinkFileParams.TargetDir = ::IncludeTrailingBackslash(DestFullName);
- SinkFileParams.CopyParam = CopyParam;
- SinkFileParams.Params = Params;
- SinkFileParams.OperationProgress = OperationProgress;
- SinkFileParams.Skipped = false;
- SinkFileParams.Flags = Flags & ~(tfFirstLevel | tfAutoResume);
- FTerminal->ProcessDirectory(FileName, SinkFile, &SinkFileParams);
- // Do not delete directory if some of its files were skip.
- // Throw "skip file" for the directory to avoid attempt to deletion
- // of any parent directory
- if (FLAGSET(Params, cpDelete) && SinkFileParams.Skipped)
- {
- THROW_SKIP_FILE_NULL;
- }
- }
- else
- {
- // file is symlink to directory, currently do nothing, but it should be
- // reported to user
- }
- }
- }
- else
- {
- FTerminal->LogEvent(FORMAT(L"Copying \"%s\" to local directory started.", (FileName.c_str())));
- bool CanProceed = true;
- if (FileExists(DestFullName))
- {
- __int64 Size;
- __int64 MTime;
- FTerminal->OpenLocalFile(DestFullName, GENERIC_READ, NULL,
- NULL, NULL, &MTime, NULL, &Size);
- TOverwriteFileParams FileParams;
- FileParams.SourceSize = File->Size;
- FileParams.SourceTimestamp = File->Modification;
- FileParams.DestSize = Size;
- FileParams.DestTimestamp = UnixToDateTime(MTime,
- FTerminal->SessionData->DSTMode);
- unsigned int Answer = 0;
- TOverwriteMode OverwriteMode = omOverwrite;
- bool AutoResume = false;
- ConfirmOverwrite(DestFullName, OverwriteMode, OperationProgress,
- &FileParams, CopyParam, Params, AutoResume, Answer);
- switch (Answer)
- {
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- default:
- break;
- }
- }
- if (CanProceed)
- {
- // Suppose same data size to transfer as to write
- OperationProgress->SetTransferSize(File->Size);
- OperationProgress->SetLocalSize(OperationProgress->TransferSize);
- int Attrs = -1;
- FILE_OPERATION_LOOP (FMTLOAD(NOT_FILE_ERROR, (DestFullName.c_str())),
- Attrs = FileGetAttr(DestFullName);
- if ((Attrs >= 0) && FLAGSET(Attrs, faDirectory)) { EXCEPTION; }
- );
- OperationProgress->TransferingFile = false; // not set with FTP protocol
- ResetFileTransfer();
- TFileTransferData UserData;
- UnicodeString FilePath = ::UnixExtractFilePath(FileName);
- if (FilePath.IsEmpty())
- {
- FilePath = L"/";
- }
- {
- unsigned int TransferType = 2;
- // ignore file list
- TWebDAVFileListHelper Helper(this, NULL, true);
- FFileTransferCPSLimit = OperationProgress->CPSLimit;
- FFileTransferPreserveTime = CopyParam->PreserveTime;
- UserData.FileName = DestFileName;
- UserData.Params = Params;
- UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
- UserData.CopyParam = CopyParam;
- FileTransfer(FileName, DestFullName, FileNameOnly,
- FilePath, true, File->Size, TransferType, UserData, OperationProgress);
- }
- // in case dest filename is changed from overwrite dialog
- if (DestFileName != UserData.FileName)
- {
- DestFullName = TargetDir + UserData.FileName;
- Attrs = FileGetAttr(DestFullName);
- }
- Action.Destination(ExpandUNCFileName(DestFullName));
- if (Attrs == -1)
- {
- Attrs = faArchive;
- }
- int NewAttrs = CopyParam->LocalFileAttrs(*File->Rights);
- if ((NewAttrs & Attrs) != NewAttrs)
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DestFullName.c_str())),
- THROWOSIFFALSE(FileSetAttr(DestFullName, Attrs | NewAttrs) == 0);
- );
- }
- // set time
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DestFullName.c_str())),
- HANDLE Handle;
- Handle = CreateFile(DestFullName.c_str(), GENERIC_WRITE,
- FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
- FILETIME WrTime = DateTimeToFileTime(File->Modification,
- FTerminal->SessionData->DSTMode);
- bool Result = SetFileTime(Handle, &WrTime, &WrTime, &WrTime) > 0;
- CloseHandle(Handle);
- if (!Result)
- {
- Abort();
- }
- );
- }
- }
- }
- if (FLAGSET(Params, cpDelete))
- {
- // If file is directory, do not delete it recursively, because it should be
- // empty already. If not, it should not be deleted (some files were
- // skipped or some new files were copied to it, while we were downloading)
- int Params = dfNoRecursive;
- FTerminal->DeleteFile(FileName, File, &Params);
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::SinkFile(const UnicodeString FileName,
- const TRemoteFile * File, void * Param)
- {
- TSinkFileParams * Params = static_cast<TSinkFileParams *>(Param);
- assert(Params->OperationProgress);
- try
- {
- SinkRobust(FileName, File, Params->TargetDir, Params->CopyParam,
- Params->Params, Params->OperationProgress, Params->Flags);
- }
- catch (EScpSkipFile & E)
- {
- TFileOperationProgressType * OperationProgress = Params->OperationProgress;
- Params->Skipped = true;
- SUSPEND_OPERATION (
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- if (OperationProgress->Cancel)
- {
- Abort();
- }
- }
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::HandleListData(const wchar_t * Path,
- const TListDataEntry * Entries, unsigned int Count)
- {
- if (!FActive)
- {
- return false;
- }
- else if (FIgnoreFileList)
- {
- // directory listing provided implicitly by FZAPI during certain operations is ignored
- assert(FFileList == NULL);
- return false;
- }
- else
- {
- assert(FFileList != NULL);
- // this can actually fail in real life,
- // when connected to server with case insensitive paths
- assert(UnixComparePaths(AbsolutePath(FFileList->Directory, false), Path));
- USEDPARAM(Path);
- for (size_t Index = 0; Index < Count; Index++)
- {
- const TListDataEntry * Entry = &Entries[Index];
- TRemoteFile * File = new TRemoteFile();
- try
- {
- File->Terminal = FTerminal;
- File->FileName = UnicodeString(Entry->Name);
- if (wcslen(Entry->Permissions) >= 10)
- {
- try
- {
- File->Rights->Text = Entry->Permissions + 1;
- }
- catch (...)
- {
- // ignore permissions errors with WebDAV
- }
- }
- // FIXME
- UnicodeString own = Entry->OwnerGroup;
- const wchar_t * Space = wcschr(own.c_str(), ' ');
- if (Space != NULL)
- {
- File->Owner.Name = UnicodeString(own.c_str(), Space - own.c_str());
- File->Group.Name = Space + 1;
- }
- else
- {
- File->Owner.Name = Entry->OwnerGroup;
- }
- File->Size = Entry->Size;
- if (Entry->Link)
- {
- File->Type = FILETYPE_SYMLINK;
- }
- else if (Entry->Dir)
- {
- File->Type = FILETYPE_DIRECTORY;
- }
- else
- {
- File->Type = L'-';
- }
- // ModificationFmt must be set after Modification
- if (Entry->Time.HasDate)
- {
- // should be the same as ConvertRemoteTimestamp
- TDateTime Modification =
- EncodeDateVerbose(static_cast<unsigned short>(Entry->Time.Year), static_cast<unsigned short>(Entry->Time.Month),
- static_cast<unsigned short>(Entry->Time.Day));
- if (Entry->Time.HasTime)
- {
- unsigned short seconds = 0;
- if (Entry->Time.HasSeconds)
- seconds = static_cast<unsigned short>(Entry->Time.Second);
- File->Modification = Modification +
- EncodeTimeVerbose(static_cast<unsigned short>(Entry->Time.Hour),
- static_cast<unsigned short>(Entry->Time.Minute),
- seconds, 0);
- // not exact as we got year as well, but it is most probably
- // guessed by FZAPI anyway
- File->ModificationFmt = mfMDHM;
- }
- else
- {
- File->Modification = Modification;
- File->ModificationFmt = mfMDY;
- }
- }
- else
- {
- // We estimate date to be today, if we have at least time
- File->Modification = TDateTime(0.0);
- File->ModificationFmt = mfNone;
- }
- File->LastAccess = File->Modification;
- File->LinkTo = Entry->LinkTarget;
- File->Complete();
- }
- catch (Exception & E)
- {
- delete File;
- UnicodeString EntryData =
- FORMAT(L"%s/%s/%s/%lld/%d/%d/%d/%d/%d/%d/%d/%d/%d",
- (Entry->Name,
- Entry->Permissions,
- Entry->OwnerGroup,
- Entry->Size,
- int(Entry->Dir), int(Entry->Link), Entry->Time.Year, Entry->Time.Month, Entry->Time.Day,
- Entry->Time.Hour, Entry->Time.Minute, int(Entry->Time.HasTime), int(Entry->Time.HasDate)));
- throw ETerminal(&E, FMTLOAD(LIST_LINE_ERROR, (EntryData.c_str())), HELP_LIST_LINE_ERROR);
- }
- FFileList->AddFile(File);
- }
- return true;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ResetFileTransfer()
- {
- FFileTransferAbort = ftaNone;
- FFileTransferCancelled = false;
- FFileTransferResumed = 0;
- webdav::cancelled = FALSE;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadDirectoryProgress(__int64 Bytes)
- {
- // with WebDAV we do not know exactly how many entries we have received,
- // instead we know number of bytes received only.
- // so we report approximation based on average size of entry.
- size_t Progress = static_cast<size_t>(Bytes / 80);
- if (Progress - FLastReadDirectoryProgress >= 10)
- {
- bool Cancel = false;
- FLastReadDirectoryProgress = Progress;
- FTerminal->DoReadDirectoryProgress(Progress, Cancel);
- if (Cancel)
- {
- FTerminal->DoReadDirectoryProgress(-2, Cancel);
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::DoFileTransferProgress(__int64 TransferSize,
- __int64 Bytes)
- {
- TFileOperationProgressType * OperationProgress = FTerminal->OperationProgress;
- if (!OperationProgress) return;
- OperationProgress->SetTransferSize(TransferSize);
- if (FFileTransferResumed > 0)
- {
- OperationProgress->AddResumed(FFileTransferResumed);
- FFileTransferResumed = 0;
- }
- __int64 Diff = Bytes - OperationProgress->TransferedSize;
- if (Diff >= 0)
- {
- OperationProgress->AddTransfered(Diff);
- }
- if (OperationProgress->Cancel == csCancel)
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- }
- if (FFileTransferCPSLimit != OperationProgress->CPSLimit)
- {
- FFileTransferCPSLimit = OperationProgress->CPSLimit;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::FileTransferProgress(__int64 TransferSize,
- __int64 Bytes)
- {
- TGuard Guard(FTransferStatusCriticalSection);
- DoFileTransferProgress(TransferSize, Bytes);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::FileTransfer(const UnicodeString FileName,
- const UnicodeString LocalFile, const UnicodeString RemoteFile,
- const UnicodeString RemotePath, bool Get, __int64 Size, int Type,
- TFileTransferData & UserData, TFileOperationProgressType * OperationProgress)
- {
- FCurrentOperationProgress = OperationProgress;
- FILE_OPERATION_LOOP (FMTLOAD(TRANSFER_ERROR, (FileName.c_str())),
- UnicodeString FullRemoteFileName = RemotePath + RemoteFile;
- bool Result = false;
- if (Get)
- {
- HANDLE LocalFileHandle = 0;
- FTerminal->CreateLocalFile(LocalFile,
- OperationProgress, &LocalFileHandle, true);
- Result = WebDAVGetFile(FullRemoteFileName.c_str(), &LocalFileHandle);
- if (!Result)
- {
- ::CloseHandle(LocalFileHandle);
- }
- }
- else
- {
- Result = WebDAVPutFile(FullRemoteFileName.c_str(), LocalFile.c_str(), Size);
- }
- if (!Result)
- EXCEPTION;
- );
- switch (FFileTransferAbort)
- {
- case ftaSkip:
- THROW_SKIP_FILE(NULL, L"");
- case ftaCancel:
- Abort();
- break;
- }
- if (!FFileTransferCancelled)
- {
- // show completion of transfer
- // call non-guarded variant to avoid deadlock with keepalives
- // (we are not waiting for reply anymore so keepalives are free to proceed)
- DoFileTransferProgress(OperationProgress->TransferSize, OperationProgress->TransferSize);
- }
- }
- bool TWebDAVFileSystem::SendPropFindRequest(const wchar_t * path, int & responseCode)
- {
- assert(path);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
- if (err) return false;
- err = webdav::client_send_propfind_request(
- FSession,
- remote_path,
- &responseCode,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVCheckExisting(const wchar_t * path, int & is_dir)
- {
- assert(path);
- is_dir = 0;
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- webdav::node_kind_t kind = webdav::node_none;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
- if (err) return false;
- err = webdav::client_check_path(
- FSession,
- remote_path,
- &kind,
- pool
- );
- if (kind != webdav::node_none)
- is_dir = kind == webdav::node_dir;
- webdav_pool_destroy(pool);
- return (err == WEBDAV_NO_ERROR) && (kind != webdav::node_none);
- }
- bool TWebDAVFileSystem::WebDAVMakeDirectory(const wchar_t * path)
- {
- assert(path);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
- if (err) return false;
- err = webdav::client_make_directory(
- FSession,
- remote_path,
- NULL,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVGetList(const UnicodeString Directory)
- {
- webdav::listdataentry_vector_t Entries;
- assert(FSession);
- webdav::list_func_baton_t baton = {0};
- baton.verbose = true;
- baton.entries = &Entries;
- baton.session = FSession;
- baton.pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(Directory).c_str(), baton.pool);
- if (err) return false;
- err = webdav::client_list2(
- FSession,
- remote_path,
- webdav::depth_immediates,
- WEBDAV_DIRENT_ALL,
- webdav::list_func,
- &baton,
- baton.pool
- );
- TListDataEntry * pEntries = !Entries.empty() ? &Entries[0] : NULL;
- HandleListData(Directory.c_str(), pEntries, Entries.size());
- webdav_pool_destroy(baton.pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVGetFile(const wchar_t * remotePath,
- HANDLE * LocalFileHandle)
- {
- assert(remotePath && *remotePath);
- assert(LocalFileHandle);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(remotePath).c_str(), pool);
- if (err) return false;
- err = webdav::client_get_file(
- FSession,
- remote_path,
- LocalFileHandle,
- pool);
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVPutFile(const wchar_t * remotePath, const wchar_t * localPath, const unsigned __int64 /*fileSize*/)
- {
- assert(remotePath && *remotePath);
- assert(localPath && *localPath);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- const char * local_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(remotePath).c_str(), pool);
- if (err) return false;
- err = webdav::path_cstring_to_utf8(&local_path, AnsiString(localPath).c_str(), pool);
- if (err) return false;
- err = webdav::client_put_file(
- FSession,
- remote_path,
- local_path,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVRenameFile(const wchar_t * srcPath, const wchar_t * dstPath)
- {
- assert(srcPath && *srcPath);
- assert(dstPath && *dstPath);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * src_path = NULL;
- const char * dst_path = NULL;
- err = webdav::path_cstring_to_utf8(&src_path, AnsiString(srcPath).c_str(), pool);
- if (err) return false;
- err = webdav::path_cstring_to_utf8(&dst_path, AnsiString(dstPath).c_str(), pool);
- if (err) return false;
- err = webdav::client_move_file_or_directory(
- FSession,
- src_path,
- dst_path,
- NULL,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVDeleteFile(const wchar_t * path)
- {
- assert(path);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
- if (err) return false;
- err = webdav::client_delete_file(
- FSession,
- remote_path,
- NULL,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::OpenURL(const UnicodeString & session_URL,
- apr_pool_t * pool)
- {
- webdav::client_ctx_t * ctx = NULL;
- WEBDAV_ERR(client_create_context(&ctx, pool));
- const char * auth_username = NULL;
- const char * auth_password = NULL;
- WEBDAV_ERR(webdav::utf_cstring_to_utf8(&auth_username,
- AnsiString(FTerminal->SessionData->UserNameExpanded).c_str(), pool));
- WEBDAV_ERR(webdav::utf_cstring_to_utf8(&auth_password,
- AnsiString(FTerminal->SessionData->Password).c_str(), pool));
- webdav::auth_baton_t * ab = NULL;
- webdav::auth_baton_create(&ab, pool);
- webdav::auth_baton_init(ab,
- FALSE, // non_interactive
- auth_username,
- auth_password,
- FALSE, // no_auth_cache
- TRUE, // trust_server_cert
- this,
- webdav::check_cancel, ab,
- pool);
- ctx->auth_baton = ab;
- // Set up our cancellation support.
- ctx->cancel_func = webdav::check_cancel;
- ctx->cancel_baton = ab;
- ctx->progress_func = webdav::progress_func;
- ctx->progress_baton = ctx;
- webdav::session_t * session_p = NULL;
- const char * corrected_url = NULL;
- AnsiString base_url = AnsiString(session_URL).c_str();
- const char * base_url_encoded = webdav::path_uri_encode(base_url.c_str(), pool);
- WEBDAV_ERR(webdav::client_open_session_internal(
- &session_p,
- &corrected_url,
- base_url_encoded,
- ctx,
- pool));
- const char * url = NULL;
- if (corrected_url)
- {
- url = apr_pstrdup(pool, corrected_url);
- }
- else
- {
- url = apr_pstrdup(pool, base_url_encoded);
- }
- ne_uri * uri = NULL;
- if (WEBDAV_NO_ERROR == webdav::parse_ne_uri(&uri, url, pool))
- {
- FCurrentDirectory = uri->path;
- FHasTrailingSlash = (FCurrentDirectory.Length() > 0) && (FCurrentDirectory[FCurrentDirectory.Length()] == L'/');
- }
- FSession = session_p;
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- webdav::error_t TWebDAVFileSystem::GetServerSettings(
- int * proxy_method,
- const char ** proxy_host,
- unsigned int * proxy_port,
- const char ** proxy_username,
- const char ** proxy_password,
- int * timeout_seconds,
- int * neon_debug,
- const char ** neon_debug_file_name,
- bool * compression,
- const char ** pk11_provider,
- const char ** ssl_authority_file,
- apr_pool_t * pool)
- {
- // If we find nothing, default to nulls.
- *proxy_method = 0;
- *proxy_host = NULL;
- *proxy_port = (unsigned int)-1;
- *proxy_username = NULL;
- *proxy_password = NULL;
- *pk11_provider = NULL;
- *ssl_authority_file = NULL;
- TSessionData * Data = FTerminal->SessionData;
- TConfiguration * Configuration = FTerminal->Configuration;
- {
- TProxyMethod ProxyMethod = Data->ProxyMethod;
- *proxy_method = (int)ProxyMethod;
- if (ProxyMethod != (TProxyMethod)::pmNone)
- {
- WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_host, AnsiString(Data->ProxyHost).c_str(), pool));
- WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_username, AnsiString(Data->ProxyUsername).c_str(), pool));
- WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_password, AnsiString(Data->ProxyPassword).c_str(), pool));
- }
- }
- // Apply non-proxy-specific settings regardless of exceptions:
- if (compression)
- *compression = Data->Compression;
- int l_debug = Configuration->ActualLogProtocol >= 1 ? 1 : 0;
- *pk11_provider = "";
- *ssl_authority_file = apr_pstrdup(pool, AnsiString(Data->PublicKeyFile).c_str());
- {
- int l_proxy_port = Data->ProxyPort;
- if (l_proxy_port < 0)
- {
- return webdav::error_create(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "Invalid URL: negative proxy port number");
- }
- if (l_proxy_port > 65535)
- {
- return webdav::error_create(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "Invalid URL: proxy port number greater "
- "than maximum TCP port number 65535");
- }
- *proxy_port = l_proxy_port;
- }
- {
- int l_timeout = Data->Timeout;
- if (l_timeout < 0)
- return webdav::error_create(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Invalid config: negative timeout value");
- *timeout_seconds = l_timeout;
- }
- if (l_debug)
- {
- *neon_debug = l_debug;
- if (Configuration->LogToFile)
- {
- WEBDAV_ERR(webdav::path_cstring_to_utf8(neon_debug_file_name,
- AnsiString(GetExpandedLogFileName(
- Configuration->LogFileName,
- Data)).c_str(), pool));
- }
- else
- {
- *neon_debug_file_name = NULL;
- }
- }
- else
- {
- *neon_debug = 0;
- *neon_debug_file_name = NULL;
- }
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::VerifyCertificate(
- const char * Prompt, const char * fingerprint,
- unsigned int & RequestResult)
- {
- RequestResult = 0;
- TClipboardHandler ClipboardHandler;
- ClipboardHandler.Text = fingerprint;
- TQueryButtonAlias Aliases[1];
- Aliases[0].Button = qaRetry;
- Aliases[0].Alias = LoadStr(COPY_KEY_BUTTON);
- Aliases[0].OnClick = &ClipboardHandler.Copy;
- TQueryParams Params;
- Params.HelpKeyword = HELP_VERIFY_CERTIFICATE;
- Params.NoBatchAnswers = qaYes | qaRetry;
- Params.Aliases = Aliases;
- Params.AliasesCount = LENOF(Aliases);
- unsigned int Answer = FTerminal->QueryUser(
- FMTLOAD(VERIFY_CERT_PROMPT3, (UnicodeString(Prompt).c_str())),
- NULL, qaYes | qaNo | qaCancel | qaRetry, &Params, qtWarning);
- RequestResult = Answer;
- switch (RequestResult)
- {
- case qaCancel:
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- break;
- }
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::AskForClientCertificateFilename(
- const char ** cert_file, unsigned int & RequestResult,
- apr_pool_t * pool)
- {
- RequestResult = 0;
- TSessionData * Data = FTerminal->SessionData;
- UnicodeString FileName;
- if (!FTerminal->PromptUser(Data, pkFileName, LoadStr(CERT_FILENAME_PROMPT_TITLE), L"",
- LoadStr(CERT_FILENAME_PROMPT), true, 0, FileName))
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- return WEBDAV_ERR_CANCELLED;
- }
- WEBDAV_ERR(webdav::path_cstring_to_utf8(cert_file, AnsiString(FileName).c_str(), pool));
- RequestResult = qaOK;
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::AskForUsername(
- const char ** user_name, unsigned int & RequestResult,
- apr_pool_t * pool)
- {
- RequestResult = 0;
- TSessionData * Data = FTerminal->SessionData;
- UnicodeString UserName = Data->UserNameExpanded;
- if (!FTerminal->PromptUser(Data, pkUserName, LoadStr(USERNAME_TITLE), L"",
- LoadStr(USERNAME_PROMPT2), true, 0, UserName))
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- return WEBDAV_ERR_CANCELLED;
- }
- WEBDAV_ERR(webdav::path_cstring_to_utf8(user_name, AnsiString(UserName).c_str(), pool));
- RequestResult = qaOK;
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::AskForUserPassword(
- const char ** password,
- unsigned int & RequestResult,
- apr_pool_t * pool)
- {
- RequestResult = 0;
- TSessionData * Data = FTerminal->SessionData;
- UnicodeString Password = Data->Password;
- if (!FTerminal->PromptUser(Data, pkPassword, LoadStr(PASSWORD_TITLE), L"",
- LoadStr(PASSWORD_PROMPT), false, 0, Password))
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- return WEBDAV_ERR_CANCELLED;
- }
- WEBDAV_ERR(webdav::path_cstring_to_utf8(password, AnsiString(Password).c_str(), pool));
- RequestResult = qaOK;
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- webdav::error_t TWebDAVFileSystem::AskForPassphrase(
- const char ** passphrase,
- const char * realm,
- unsigned int & RequestResult,
- apr_pool_t * pool)
- {
- RequestResult = 0;
- TSessionData * Data = FTerminal->SessionData;
- UnicodeString Passphrase = Data->UserNameExpanded;
- UnicodeString Prompt = FORMAT(LoadStr(PROMPT_KEY_PASSPHRASE), (UnicodeString(realm)));
- if (!FTerminal->PromptUser(Data, pkPassphrase, LoadStr(PASSPHRASE_TITLE), L"",
- Prompt, false, 0, Passphrase))
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- return WEBDAV_ERR_CANCELLED;
- }
- WEBDAV_ERR(webdav::path_cstring_to_utf8(passphrase, AnsiString(Passphrase).c_str(), pool));
- RequestResult = qaOK;
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::SimplePrompt(
- const char * prompt_text,
- const char * prompt_string,
- unsigned int & RequestResult)
- {
- RequestResult = 0;
- TStrings * MoreMessages = new TStringList();
- try
- {
- MoreMessages->Add(UnicodeString(prompt_string));
- unsigned int Answer = FTerminal->QueryUser(
- UnicodeString(prompt_text),
- MoreMessages, qaYes | qaNo | qaCancel, NULL, qtConfirmation);
- RequestResult = Answer;
- }
- __finally
- {
- delete MoreMessages;
- }
- return RequestResult == qaCancel ? WEBDAV_ERR_CANCELLED : WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::CreateStorage(
- THierarchicalStorage *& Storage)
- {
- Storage =
- FTerminal->Configuration->CreateScpStorage(false);
- return WEBDAV_NO_ERROR;
- }
- unsigned long TWebDAVFileSystem::AdjustToCPSLimit(unsigned long len)
- {
- return FCurrentOperationProgress ? FCurrentOperationProgress->AdjustToCPSLimit(len) : len;
- }
- bool TWebDAVFileSystem::GetIsCancelled()
- {
- TFileOperationProgressType * OperationProgress = FCurrentOperationProgress;
- return (OperationProgress && OperationProgress->Cancel == csCancel);
- }
- //------------------------------------------------------------------------------
|