1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228 |
- //---------------------------------------------------------------------------
- #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->HostName;
- size_t Port = Data->PortNumber;
- UnicodeString ProtocolName = !Ssl ? L"http" : L"https";
- UnicodeString UserName = Data->UserName;
- UnicodeString Path = Data->RemoteDirectory;
- UnicodeString Url = FORMAT(L"%s://%s:%d%s", (ProtocolName.c_str(), HostName.c_str(), Port, Path.c_str()));
- FPasswordFailed = false;
- FTerminal->Information(LoadStr(STATUS_CONNECT), true);
- for (int I = 0; I < 5; I++)
- {
- FActive = false;
- try
- {
- FActive = (WEBDAV_NO_ERROR == OpenURL(Url, webdav_pool));
- if (FActive)
- {
- break;
- }
- }
- catch (...)
- {
- if (FFileTransferCancelled)
- break;
- apr_sleep(200000); // 0.2 sec
- }
- }
- if (!FActive)
- {
- FTerminal->Closed();
- throw Exception(LoadStr(CONNECTION_FAILED));
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Close()
- {
- assert(FActive);
- FTerminal->Closed();
- FActive = false;
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::GetActive()
- {
- return FActive;
- }
- //---------------------------------------------------------------------------
- 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;
- FTerminal->LogEvent(FORMAT(L"File: \"%s\"", (FileName.c_str())));
- bool CanProceed = false;
- UnicodeString FileNameOnly =
- CopyParam->ChangeFileName(ExtractFileName(FileName, false), osLocal, true);
- if (CheckExistence)
- {
- TRemoteFile * File = FTerminal->FFiles->FindFile(FileNameOnly);
- if (File != NULL)
- {
- unsigned int Answer = 0;
- if (File->IsDirectory)
- {
- UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
- TQueryParams QueryParams(qpNeverAskAgainCheck);
- SUSPEND_OPERATION (
- Answer = FTerminal->ConfirmFileOverwrite(
- FileNameOnly /*not used*/, NULL,
- qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
- &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
- );
- switch (Answer)
- {
- case qaYes:
- CanProceed = true;
- break;
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- break;
- default:
- break;
- }
- }
- else
- {
- __int64 Size;
- __int64 MTime;
- TOverwriteFileParams FileParams;
- FTerminal->OpenLocalFile(FileName, GENERIC_READ,
- NULL, NULL, NULL, &MTime, NULL,
- &Size);
- FileParams.SourceSize = Size;
- FileParams.SourceTimestamp = UnixToDateTime(MTime,
- FTerminal->SessionData->DSTMode);
- FileParams.DestSize = File->Size;
- FileParams.DestTimestamp = File->Modification;
- TOverwriteMode OverwriteMode = omOverwrite;
- bool AutoResume = false;
- ConfirmOverwrite(FileNameOnly, OverwriteMode, OperationProgress,
- &FileParams, CopyParam, Params, AutoResume, Answer);
- switch (Answer)
- {
- case qaYes:
- CanProceed = true;
- break;
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- break;
- default:
- break;
- }
- }
- }
- else
- {
- CanProceed = true;
- }
- }
- else
- {
- CanProceed = true;
- }
- if (CanProceed)
- {
- Action.FileName(ExpandUNCFileName(FileName));
- OperationProgress->SetFile(FileName, false);
- if (!FTerminal->AllowLocalFileTransfer(FileName, CopyParam))
- {
- FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
- THROW_SKIP_FILE_NULL;
- }
- __int64 Size;
- int Attrs;
- FTerminal->OpenLocalFile(FileName, GENERIC_READ, &Attrs,
- NULL, NULL, NULL, NULL, &Size);
- OperationProgress->SetFileInProgress();
- bool Dir = FLAGSET(Attrs, faDirectory);
- if (Dir)
- {
- Action.Cancel();
- WebDAVDirectorySource(IncludeTrailingBackslash(FileName), TargetDir,
- Attrs, CopyParam, Params, OperationProgress, Flags);
- }
- else
- {
- UnicodeString DestFileName = CopyParam->ChangeFileName(ExtractFileName(FileName, false),
- osLocal, FLAGSET(Flags, tfFirstLevel));
- FTerminal->LogEvent(FORMAT(L"Copying \"%s\" to remote directory started.", (FileName.c_str())));
- OperationProgress->SetLocalSize(Size);
- // Suppose same data size to transfer as to read
- // (not true with ASCII transfer)
- OperationProgress->SetTransferSize(OperationProgress->LocalSize);
- OperationProgress->TransferingFile = false;
- // Will we use ASCII of BINARY file transfer?
- TFileMasks::TParams MaskParams;
- MaskParams.Size = Size;
- ResetFileTransfer();
- TFileTransferData UserData;
- {
- unsigned int TransferType = 2;
- // ignore file list
- TWebDAVFileListHelper Helper(this, NULL, true);
- FFileTransferCPSLimit = OperationProgress->CPSLimit;
- // not used for uploads anyway
- FFileTransferPreserveTime = CopyParam->PreserveTime;
- // not used for uploads, but we get new name (if any) back in this field
- UserData.FileName = DestFileName;
- UserData.Params = Params;
- UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
- UserData.CopyParam = CopyParam;
- FileTransfer(FileName, FileName, DestFileName,
- TargetDir, false, Size, TransferType, UserData, OperationProgress);
- }
- UnicodeString DestFullName = TargetDir + UserData.FileName;
- // only now, we know the final destination
- Action.Destination(DestFullName);
- }
- // TODO : Delete also read-only files.
- if (FLAGSET(Params, cpDelete))
- {
- if (!Dir)
- {
- FILE_OPERATION_LOOP (FMTLOAD(DELETE_LOCAL_FILE_ERROR, (FileName.c_str())),
- THROWOSIFFALSE(::DeleteFile(FileName.c_str()));
- )
- }
- }
- else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (FileName.c_str())),
- THROWOSIFFALSE(FileSetAttr(FileName, Attrs & ~faArchive) == 0);
- )
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::WebDAVDirectorySource(const UnicodeString DirectoryName,
- const UnicodeString TargetDir, int Attrs, const TCopyParamType * CopyParam,
- int Params, TFileOperationProgressType * OperationProgress, unsigned int Flags)
- {
- UnicodeString DestDirectoryName = CopyParam->ChangeFileName(
- ExtractFileName(ExcludeTrailingBackslash(DirectoryName), false), osLocal,
- FLAGSET(Flags, tfFirstLevel));
- UnicodeString DestFullName = UnixIncludeTrailingBackslash(TargetDir + DestDirectoryName);
- // create DestFullName if it does not exist
- int IsDir = 0;
- bool Exists = WebDAVCheckExisting(DestFullName.c_str(), IsDir);
- if (!Exists)
- {
- CreateDirectory(DestFullName);
- }
- OperationProgress->SetFile(DirectoryName);
- WIN32_FIND_DATA SearchRec;
- bool FindOK = false;
- HANDLE findHandle = 0;
- FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
- UnicodeString path = DirectoryName + L"*.*";
- findHandle = FindFirstFile(path.c_str(), &SearchRec);
- FindOK = (findHandle != 0);
- if (!FindOK)
- {
- FindCheck(GetLastError());
- }
- );
- bool CreateDir = true;
- try
- {
- while (FindOK && !OperationProgress->Cancel)
- {
- UnicodeString FileName = DirectoryName + SearchRec.cFileName;
- try
- {
- if ((wcscmp(SearchRec.cFileName, THISDIRECTORY) != 0) && (wcscmp(SearchRec.cFileName, PARENTDIRECTORY) != 0))
- {
- WebDAVSourceRobust(FileName, DestFullName, CopyParam, Params, OperationProgress,
- Flags & ~(tfFirstLevel | tfAutoResume));
- // if any file got uploaded (i.e. there were any file in the
- // directory and at least one was not skipped),
- // do not try to create the directory,
- // as it should be already created by FZAPI during upload
- CreateDir = false;
- }
- }
- catch (EScpSkipFile & E)
- {
- // If ESkipFile occurs, just log it and continue with next file
- SUSPEND_OPERATION (
- // here a message to user was displayed, which was not appropriate
- // when user refused to overwrite the file in subdirectory.
- // hopefully it won't be missing in other situations.
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- }
- FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
- FindOK = (::FindNextFile(findHandle, &SearchRec) != 0);
- if (!FindOK)
- {
- FindCheck(GetLastError());
- }
- );
- }
- }
- __finally
- {
- ::FindClose(findHandle);
- }
- if (CreateDir)
- {
- TRemoteProperties Properties;
- if (CopyParam->PreserveRights)
- {
- Properties.Valid = TValidProperties() << vpRights;
- Properties.Rights = CopyParam->RemoteFileRights(Attrs);
- }
- try
- {
- FTerminal->SetExceptionOnFail(true);
- try
- {
- FTerminal->CreateDirectory(DestFullName, &Properties);
- }
- __finally
- {
- FTerminal->SetExceptionOnFail(false);
- }
- }
- catch (...)
- {
- TRemoteFile * File = NULL;
- // ignore non-fatal error when the directory already exists
- UnicodeString fn = UnixExcludeTrailingBackslash(DestFullName);
- if (fn.IsEmpty())
- {
- fn = L"/";
- }
- bool Rethrow =
- !FTerminal->GetActive() ||
- !FTerminal->FileExists(fn, &File) ||
- (File && !File->IsDirectory);
- delete File;
- if (Rethrow)
- {
- throw;
- }
- }
- }
- // TODO : Delete also read-only directories.
- // TODO : Show error message on failure.
- if (!OperationProgress->Cancel)
- {
- if (FLAGSET(Params, cpDelete))
- {
- RemoveDir(DirectoryName);
- }
- else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DirectoryName.c_str())),
- THROWOSIFFALSE(FileSetAttr(DirectoryName, Attrs & ~faArchive) == 0);
- )
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CopyToLocal(TStrings * FilesToCopy,
- const UnicodeString TargetDir, const TCopyParamType * CopyParam,
- int Params, TFileOperationProgressType * OperationProgress,
- TOnceDoneOperation & OnceDoneOperation)
- {
- Params &= ~cpAppend;
- UnicodeString FullTargetDir = ::IncludeTrailingBackslash(TargetDir);
- int Index = 0;
- while (Index < FilesToCopy->Count && !OperationProgress->Cancel)
- {
- UnicodeString FileName = FilesToCopy->Strings[Index];
- const TRemoteFile * File = dynamic_cast<const TRemoteFile *>(FilesToCopy->Objects[Index]);
- bool Success = false;
- FTerminal->SetExceptionOnFail(true);
- try
- {
- try
- {
- SinkRobust(AbsolutePath(FileName, false), File, FullTargetDir, CopyParam, Params,
- OperationProgress, tfFirstLevel);
- Success = true;
- }
- catch (EScpSkipFile & E)
- {
- SUSPEND_OPERATION (
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- }
- }
- __finally
- {
- OperationProgress->Finish(FileName, Success, OnceDoneOperation);
- FTerminal->SetExceptionOnFail(false);
- }
- Index++;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::SinkRobust(const UnicodeString FileName,
- const TRemoteFile * File, const UnicodeString TargetDir,
- const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags)
- {
- // the same in TSFTPFileSystem
- bool Retry;
- TDownloadSessionAction Action(FTerminal->ActionLog);
- do
- {
- Retry = false;
- try
- {
- Sink(FileName, File, TargetDir, CopyParam, Params, OperationProgress,
- Flags, Action);
- }
- catch (Exception & E)
- {
- Retry = true;
- if (FTerminal->GetActive() ||
- !FTerminal->QueryReopen(&E, ropNoReadDirectory, OperationProgress))
- {
- FTerminal->RollbackAction(Action, OperationProgress, &E);
- throw;
- }
- }
- if (Retry)
- {
- OperationProgress->RollbackTransfer();
- Action.Restart();
- assert(File != NULL);
- if (!File->IsDirectory)
- {
- // prevent overwrite confirmations
- Params |= cpNoConfirmation;
- Flags |= tfAutoResume;
- }
- }
- }
- while (Retry);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Sink(const UnicodeString FileName,
- const TRemoteFile * File, const UnicodeString TargetDir,
- const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags,
- TDownloadSessionAction & Action)
- {
- UnicodeString FileNameOnly = UnixExtractFileName(FileName);
- Action.FileName(FileName);
- assert(File);
- TFileMasks::TParams MaskParams;
- MaskParams.Size = File->Size;
- if (!CopyParam->AllowTransfer(FileName, osRemote, File->IsDirectory, MaskParams))
- {
- FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
- THROW_SKIP_FILE_NULL;
- }
- FTerminal->LogEvent(FORMAT(L"File: \"%s\"", (FileName.c_str())));
- OperationProgress->SetFile(FileNameOnly);
- UnicodeString DestFileName = CopyParam->ChangeFileName(FileNameOnly,
- osRemote, FLAGSET(Flags, tfFirstLevel));
- UnicodeString DestFullName = TargetDir + DestFileName;
- if (File->IsDirectory)
- {
- bool CanProceed = true;
- if (::DirectoryExists(DestFullName))
- {
- unsigned int Answer = 0;
- UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
- TQueryParams QueryParams(qpNeverAskAgainCheck);
- SUSPEND_OPERATION (
- Answer = FTerminal->ConfirmFileOverwrite(
- FileNameOnly /*not used*/, NULL,
- qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
- &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
- );
- switch (Answer)
- {
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- default:
- break;
- }
- }
- if (CanProceed)
- {
- Action.Cancel();
- if (!File->IsSymLink)
- {
- FILE_OPERATION_LOOP (FMTLOAD(NOT_DIRECTORY_ERROR, (DestFullName.c_str())),
- int Attrs = FileGetAttr(DestFullName);
- if (FLAGCLEAR(Attrs, faDirectory)) { EXCEPTION; }
- );
- FILE_OPERATION_LOOP (FMTLOAD(CREATE_DIR_ERROR, (DestFullName.c_str())),
- 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);
- }
- //------------------------------------------------------------------------------
|