dataprovider.go 162 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698
  1. // Copyright (C) 2019 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. // Package dataprovider provides data access.
  15. // It abstracts different data providers using a common API.
  16. package dataprovider
  17. import (
  18. "bufio"
  19. "bytes"
  20. "context"
  21. "crypto/md5"
  22. "crypto/rsa"
  23. "crypto/sha1"
  24. "crypto/sha256"
  25. "crypto/sha512"
  26. "crypto/subtle"
  27. "crypto/x509"
  28. "encoding/base64"
  29. "encoding/hex"
  30. "encoding/json"
  31. "encoding/pem"
  32. "errors"
  33. "fmt"
  34. "hash"
  35. "io"
  36. "net"
  37. "net/http"
  38. "net/url"
  39. "os"
  40. "os/exec"
  41. "path"
  42. "path/filepath"
  43. "regexp"
  44. "runtime"
  45. "slices"
  46. "strconv"
  47. "strings"
  48. "sync"
  49. "sync/atomic"
  50. "time"
  51. "github.com/GehirnInc/crypt"
  52. "github.com/GehirnInc/crypt/apr1_crypt"
  53. "github.com/GehirnInc/crypt/md5_crypt"
  54. "github.com/GehirnInc/crypt/sha256_crypt"
  55. "github.com/GehirnInc/crypt/sha512_crypt"
  56. "github.com/alexedwards/argon2id"
  57. "github.com/go-chi/render"
  58. "github.com/rs/xid"
  59. "github.com/sftpgo/sdk"
  60. passwordvalidator "github.com/wagslane/go-password-validator"
  61. "golang.org/x/crypto/bcrypt"
  62. "golang.org/x/crypto/pbkdf2"
  63. "golang.org/x/crypto/ssh"
  64. "github.com/drakkan/sftpgo/v2/internal/command"
  65. "github.com/drakkan/sftpgo/v2/internal/httpclient"
  66. "github.com/drakkan/sftpgo/v2/internal/kms"
  67. "github.com/drakkan/sftpgo/v2/internal/logger"
  68. "github.com/drakkan/sftpgo/v2/internal/mfa"
  69. "github.com/drakkan/sftpgo/v2/internal/plugin"
  70. "github.com/drakkan/sftpgo/v2/internal/util"
  71. "github.com/drakkan/sftpgo/v2/internal/vfs"
  72. )
  73. const (
  74. // SQLiteDataProviderName defines the name for SQLite database provider
  75. SQLiteDataProviderName = "sqlite"
  76. // PGSQLDataProviderName defines the name for PostgreSQL database provider
  77. PGSQLDataProviderName = "postgresql"
  78. // MySQLDataProviderName defines the name for MySQL database provider
  79. MySQLDataProviderName = "mysql"
  80. // BoltDataProviderName defines the name for bbolt key/value store provider
  81. BoltDataProviderName = "bolt"
  82. // MemoryDataProviderName defines the name for memory provider
  83. MemoryDataProviderName = "memory"
  84. // CockroachDataProviderName defines the for CockroachDB provider
  85. CockroachDataProviderName = "cockroachdb"
  86. // DumpVersion defines the version for the dump.
  87. // For restore/load we support the current version and the previous one
  88. DumpVersion = 16
  89. argonPwdPrefix = "$argon2id$"
  90. bcryptPwdPrefix = "$2a$"
  91. pbkdf2SHA1Prefix = "$pbkdf2-sha1$"
  92. pbkdf2SHA256Prefix = "$pbkdf2-sha256$"
  93. pbkdf2SHA512Prefix = "$pbkdf2-sha512$"
  94. pbkdf2SHA256B64SaltPrefix = "$pbkdf2-b64salt-sha256$"
  95. md5cryptPwdPrefix = "$1$"
  96. md5cryptApr1PwdPrefix = "$apr1$"
  97. sha256cryptPwdPrefix = "$5$"
  98. sha512cryptPwdPrefix = "$6$"
  99. yescryptPwdPrefix = "$y$"
  100. md5DigestPwdPrefix = "{MD5}"
  101. sha256DigestPwdPrefix = "{SHA256}"
  102. sha512DigestPwdPrefix = "{SHA512}"
  103. trackQuotaDisabledError = "please enable track_quota in your configuration to use this method"
  104. operationAdd = "add"
  105. operationUpdate = "update"
  106. operationDelete = "delete"
  107. sqlPrefixValidChars = "abcdefghijklmnopqrstuvwxyz_0123456789"
  108. maxHookResponseSize = 1048576 // 1MB
  109. iso8601UTCFormat = "2006-01-02T15:04:05Z"
  110. )
  111. // Supported algorithms for hashing passwords.
  112. // These algorithms can be used when SFTPGo hashes a plain text password
  113. const (
  114. HashingAlgoBcrypt = "bcrypt"
  115. HashingAlgoArgon2ID = "argon2id"
  116. )
  117. // ordering constants
  118. const (
  119. OrderASC = "ASC"
  120. OrderDESC = "DESC"
  121. )
  122. const (
  123. protocolSSH = "SSH"
  124. protocolFTP = "FTP"
  125. protocolWebDAV = "DAV"
  126. protocolHTTP = "HTTP"
  127. )
  128. // Dump scopes
  129. const (
  130. DumpScopeUsers = "users"
  131. DumpScopeFolders = "folders"
  132. DumpScopeGroups = "groups"
  133. DumpScopeAdmins = "admins"
  134. DumpScopeAPIKeys = "api_keys"
  135. DumpScopeShares = "shares"
  136. DumpScopeActions = "actions"
  137. DumpScopeRules = "rules"
  138. DumpScopeRoles = "roles"
  139. DumpScopeIPLists = "ip_lists"
  140. DumpScopeConfigs = "configs"
  141. )
  142. const (
  143. fieldUsername = 1
  144. fieldName = 2
  145. fieldIPNet = 3
  146. )
  147. var (
  148. // SupportedProviders defines the supported data providers
  149. SupportedProviders = []string{SQLiteDataProviderName, PGSQLDataProviderName, MySQLDataProviderName,
  150. BoltDataProviderName, MemoryDataProviderName, CockroachDataProviderName}
  151. // ValidPerms defines all the valid permissions for a user
  152. ValidPerms = []string{PermAny, PermListItems, PermDownload, PermUpload, PermOverwrite, PermCreateDirs, PermRename,
  153. PermRenameFiles, PermRenameDirs, PermDelete, PermDeleteFiles, PermDeleteDirs, PermCopy, PermCreateSymlinks,
  154. PermChmod, PermChown, PermChtimes}
  155. // ValidLoginMethods defines all the valid login methods
  156. ValidLoginMethods = []string{SSHLoginMethodPublicKey, LoginMethodPassword, SSHLoginMethodPassword,
  157. SSHLoginMethodKeyboardInteractive, SSHLoginMethodKeyAndPassword, SSHLoginMethodKeyAndKeyboardInt,
  158. LoginMethodTLSCertificate, LoginMethodTLSCertificateAndPwd}
  159. // SSHMultiStepsLoginMethods defines the supported Multi-Step Authentications
  160. SSHMultiStepsLoginMethods = []string{SSHLoginMethodKeyAndPassword, SSHLoginMethodKeyAndKeyboardInt}
  161. // ErrNoAuthTried defines the error for connection closed before authentication
  162. ErrNoAuthTried = errors.New("no auth tried")
  163. // ErrNotImplemented defines the error for features not supported for a particular data provider
  164. ErrNotImplemented = errors.New("feature not supported with the configured data provider")
  165. // ValidProtocols defines all the valid protcols
  166. ValidProtocols = []string{protocolSSH, protocolFTP, protocolWebDAV, protocolHTTP}
  167. // MFAProtocols defines the supported protocols for multi-factor authentication
  168. MFAProtocols = []string{protocolHTTP, protocolSSH, protocolFTP}
  169. // ErrNoInitRequired defines the error returned by InitProvider if no inizialization/update is required
  170. ErrNoInitRequired = errors.New("the data provider is up to date")
  171. // ErrInvalidCredentials defines the error to return if the supplied credentials are invalid
  172. ErrInvalidCredentials = errors.New("invalid credentials")
  173. // ErrLoginNotAllowedFromIP defines the error to return if login is denied from the current IP
  174. ErrLoginNotAllowedFromIP = errors.New("login is not allowed from this IP")
  175. // ErrDuplicatedKey occurs when there is a unique key constraint violation
  176. ErrDuplicatedKey = errors.New("duplicated key not allowed")
  177. // ErrForeignKeyViolated occurs when there is a foreign key constraint violation
  178. ErrForeignKeyViolated = errors.New("violates foreign key constraint")
  179. tz = ""
  180. isAdminCreated atomic.Bool
  181. validTLSUsernames = []string{string(sdk.TLSUsernameNone), string(sdk.TLSUsernameCN)}
  182. config Config
  183. provider Provider
  184. sqlPlaceholders []string
  185. internalHashPwdPrefixes = []string{argonPwdPrefix, bcryptPwdPrefix}
  186. hashPwdPrefixes = []string{argonPwdPrefix, bcryptPwdPrefix, pbkdf2SHA1Prefix, pbkdf2SHA256Prefix,
  187. pbkdf2SHA512Prefix, pbkdf2SHA256B64SaltPrefix, md5cryptPwdPrefix, md5cryptApr1PwdPrefix, md5DigestPwdPrefix,
  188. sha256DigestPwdPrefix, sha512DigestPwdPrefix, sha256cryptPwdPrefix, sha512cryptPwdPrefix, yescryptPwdPrefix}
  189. pbkdfPwdPrefixes = []string{pbkdf2SHA1Prefix, pbkdf2SHA256Prefix, pbkdf2SHA512Prefix, pbkdf2SHA256B64SaltPrefix}
  190. pbkdfPwdB64SaltPrefixes = []string{pbkdf2SHA256B64SaltPrefix}
  191. unixPwdPrefixes = []string{md5cryptPwdPrefix, md5cryptApr1PwdPrefix, sha256cryptPwdPrefix, sha512cryptPwdPrefix,
  192. yescryptPwdPrefix}
  193. digestPwdPrefixes = []string{md5DigestPwdPrefix, sha256DigestPwdPrefix, sha512DigestPwdPrefix}
  194. sharedProviders = []string{PGSQLDataProviderName, MySQLDataProviderName, CockroachDataProviderName}
  195. logSender = "dataprovider"
  196. sqlTableUsers string
  197. sqlTableFolders string
  198. sqlTableUsersFoldersMapping string
  199. sqlTableAdmins string
  200. sqlTableAPIKeys string
  201. sqlTableShares string
  202. sqlTableDefenderHosts string
  203. sqlTableDefenderEvents string
  204. sqlTableActiveTransfers string
  205. sqlTableGroups string
  206. sqlTableUsersGroupsMapping string
  207. sqlTableAdminsGroupsMapping string
  208. sqlTableGroupsFoldersMapping string
  209. sqlTableSharedSessions string
  210. sqlTableEventsActions string
  211. sqlTableEventsRules string
  212. sqlTableRulesActionsMapping string
  213. sqlTableTasks string
  214. sqlTableNodes string
  215. sqlTableRoles string
  216. sqlTableIPLists string
  217. sqlTableConfigs string
  218. sqlTableSchemaVersion string
  219. argon2Params *argon2id.Params
  220. lastLoginMinDelay = 10 * time.Minute
  221. usernameRegex = regexp.MustCompile("^[a-zA-Z0-9-_.~]+$")
  222. tempPath string
  223. allowSelfConnections int
  224. fnReloadRules FnReloadRules
  225. fnRemoveRule FnRemoveRule
  226. fnHandleRuleForProviderEvent FnHandleRuleForProviderEvent
  227. )
  228. func initSQLTables() {
  229. sqlTableUsers = "users"
  230. sqlTableFolders = "folders"
  231. sqlTableUsersFoldersMapping = "users_folders_mapping"
  232. sqlTableAdmins = "admins"
  233. sqlTableAPIKeys = "api_keys"
  234. sqlTableShares = "shares"
  235. sqlTableDefenderHosts = "defender_hosts"
  236. sqlTableDefenderEvents = "defender_events"
  237. sqlTableActiveTransfers = "active_transfers"
  238. sqlTableGroups = "groups"
  239. sqlTableUsersGroupsMapping = "users_groups_mapping"
  240. sqlTableGroupsFoldersMapping = "groups_folders_mapping"
  241. sqlTableAdminsGroupsMapping = "admins_groups_mapping"
  242. sqlTableSharedSessions = "shared_sessions"
  243. sqlTableEventsActions = "events_actions"
  244. sqlTableEventsRules = "events_rules"
  245. sqlTableRulesActionsMapping = "rules_actions_mapping"
  246. sqlTableTasks = "tasks"
  247. sqlTableNodes = "nodes"
  248. sqlTableRoles = "roles"
  249. sqlTableIPLists = "ip_lists"
  250. sqlTableConfigs = "configurations"
  251. sqlTableSchemaVersion = "schema_version"
  252. }
  253. // FnReloadRules defined the callback to reload event rules
  254. type FnReloadRules func()
  255. // FnRemoveRule defines the callback to remove an event rule
  256. type FnRemoveRule func(name string)
  257. // FnHandleRuleForProviderEvent define the callback to handle event rules for provider events
  258. type FnHandleRuleForProviderEvent func(operation, executor, ip, objectType, objectName, role string, object plugin.Renderer)
  259. // SetEventRulesCallbacks sets the event rules callbacks
  260. func SetEventRulesCallbacks(reload FnReloadRules, remove FnRemoveRule, handle FnHandleRuleForProviderEvent) {
  261. fnReloadRules = reload
  262. fnRemoveRule = remove
  263. fnHandleRuleForProviderEvent = handle
  264. }
  265. type schemaVersion struct {
  266. Version int
  267. }
  268. // BcryptOptions defines the options for bcrypt password hashing
  269. type BcryptOptions struct {
  270. Cost int `json:"cost" mapstructure:"cost"`
  271. }
  272. // Argon2Options defines the options for argon2 password hashing
  273. type Argon2Options struct {
  274. Memory uint32 `json:"memory" mapstructure:"memory"`
  275. Iterations uint32 `json:"iterations" mapstructure:"iterations"`
  276. Parallelism uint8 `json:"parallelism" mapstructure:"parallelism"`
  277. }
  278. // PasswordHashing defines the configuration for password hashing
  279. type PasswordHashing struct {
  280. BcryptOptions BcryptOptions `json:"bcrypt_options" mapstructure:"bcrypt_options"`
  281. Argon2Options Argon2Options `json:"argon2_options" mapstructure:"argon2_options"`
  282. // Algorithm to use for hashing passwords. Available algorithms: argon2id, bcrypt. Default: bcrypt
  283. Algo string `json:"algo" mapstructure:"algo"`
  284. }
  285. // PasswordValidationRules defines the password validation rules
  286. type PasswordValidationRules struct {
  287. // MinEntropy defines the minimum password entropy.
  288. // 0 means disabled, any password will be accepted.
  289. // Take a look at the following link for more details
  290. // https://github.com/wagslane/go-password-validator#what-entropy-value-should-i-use
  291. MinEntropy float64 `json:"min_entropy" mapstructure:"min_entropy"`
  292. }
  293. // PasswordValidation defines the password validation rules for admins and protocol users
  294. type PasswordValidation struct {
  295. // Password validation rules for SFTPGo admin users
  296. Admins PasswordValidationRules `json:"admins" mapstructure:"admins"`
  297. // Password validation rules for SFTPGo protocol users
  298. Users PasswordValidationRules `json:"users" mapstructure:"users"`
  299. }
  300. type wrappedFolder struct {
  301. Folder vfs.BaseVirtualFolder
  302. }
  303. func (w *wrappedFolder) RenderAsJSON(reload bool) ([]byte, error) {
  304. if reload {
  305. folder, err := provider.getFolderByName(w.Folder.Name)
  306. if err != nil {
  307. providerLog(logger.LevelError, "unable to reload folder before rendering as json: %v", err)
  308. return nil, err
  309. }
  310. folder.PrepareForRendering()
  311. return json.Marshal(folder)
  312. }
  313. w.Folder.PrepareForRendering()
  314. return json.Marshal(w.Folder)
  315. }
  316. // ObjectsActions defines the action to execute on user create, update, delete for the specified objects
  317. type ObjectsActions struct {
  318. // Valid values are add, update, delete. Empty slice to disable
  319. ExecuteOn []string `json:"execute_on" mapstructure:"execute_on"`
  320. // Valid values are user, admin, api_key
  321. ExecuteFor []string `json:"execute_for" mapstructure:"execute_for"`
  322. // Absolute path to an external program or an HTTP URL
  323. Hook string `json:"hook" mapstructure:"hook"`
  324. }
  325. // ProviderStatus defines the provider status
  326. type ProviderStatus struct {
  327. Driver string `json:"driver"`
  328. IsActive bool `json:"is_active"`
  329. Error string `json:"error"`
  330. }
  331. // Config defines the provider configuration
  332. type Config struct {
  333. // Driver name, must be one of the SupportedProviders
  334. Driver string `json:"driver" mapstructure:"driver"`
  335. // Database name. For driver sqlite this can be the database name relative to the config dir
  336. // or the absolute path to the SQLite database.
  337. Name string `json:"name" mapstructure:"name"`
  338. // Database host. For postgresql and cockroachdb driver you can specify multiple hosts separated by commas
  339. Host string `json:"host" mapstructure:"host"`
  340. // Database port
  341. Port int `json:"port" mapstructure:"port"`
  342. // Database username
  343. Username string `json:"username" mapstructure:"username"`
  344. // Database password
  345. Password string `json:"password" mapstructure:"password"`
  346. // Used for drivers mysql and postgresql.
  347. // 0 disable SSL/TLS connections.
  348. // 1 require ssl.
  349. // 2 set ssl mode to verify-ca for driver postgresql and skip-verify for driver mysql.
  350. // 3 set ssl mode to verify-full for driver postgresql and preferred for driver mysql.
  351. SSLMode int `json:"sslmode" mapstructure:"sslmode"`
  352. // Used for drivers mysql, postgresql and cockroachdb. Set to true to disable SNI
  353. DisableSNI bool `json:"disable_sni" mapstructure:"disable_sni"`
  354. // TargetSessionAttrs is a postgresql and cockroachdb specific option.
  355. // It determines whether the session must have certain properties to be acceptable.
  356. // It's typically used in combination with multiple host names to select the first
  357. // acceptable alternative among several hosts
  358. TargetSessionAttrs string `json:"target_session_attrs" mapstructure:"target_session_attrs"`
  359. // Path to the root certificate authority used to verify that the server certificate was signed by a trusted CA
  360. RootCert string `json:"root_cert" mapstructure:"root_cert"`
  361. // Path to the client certificate for two-way TLS authentication
  362. ClientCert string `json:"client_cert" mapstructure:"client_cert"`
  363. // Path to the client key for two-way TLS authentication
  364. ClientKey string `json:"client_key" mapstructure:"client_key"`
  365. // Custom database connection string.
  366. // If not empty this connection string will be used instead of build one using the previous parameters
  367. ConnectionString string `json:"connection_string" mapstructure:"connection_string"`
  368. // prefix for SQL tables
  369. SQLTablesPrefix string `json:"sql_tables_prefix" mapstructure:"sql_tables_prefix"`
  370. // Set the preferred way to track users quota between the following choices:
  371. // 0, disable quota tracking. REST API to scan user dir and update quota will do nothing
  372. // 1, quota is updated each time a user upload or delete a file even if the user has no quota restrictions
  373. // 2, quota is updated each time a user upload or delete a file but only for users with quota restrictions
  374. // and for virtual folders.
  375. // With this configuration the "quota scan" REST API can still be used to periodically update space usage
  376. // for users without quota restrictions
  377. TrackQuota int `json:"track_quota" mapstructure:"track_quota"`
  378. // Sets the maximum number of open connections for mysql and postgresql driver.
  379. // Default 0 (unlimited)
  380. PoolSize int `json:"pool_size" mapstructure:"pool_size"`
  381. // Users default base directory.
  382. // If no home dir is defined while adding a new user, and this value is
  383. // a valid absolute path, then the user home dir will be automatically
  384. // defined as the path obtained joining the base dir and the username
  385. UsersBaseDir string `json:"users_base_dir" mapstructure:"users_base_dir"`
  386. // Actions to execute on objects add, update, delete.
  387. // The supported objects are user, admin, api_key.
  388. // Update action will not be fired for internal updates such as the last login or the user quota fields.
  389. Actions ObjectsActions `json:"actions" mapstructure:"actions"`
  390. // Absolute path to an external program or an HTTP URL to invoke for users authentication.
  391. // Leave empty to use builtin authentication.
  392. // If the authentication succeed the user will be automatically added/updated inside the defined data provider.
  393. // Actions defined for user added/updated will not be executed in this case.
  394. // This method is slower than built-in authentication methods, but it's very flexible as anyone can
  395. // easily write his own authentication hooks.
  396. ExternalAuthHook string `json:"external_auth_hook" mapstructure:"external_auth_hook"`
  397. // ExternalAuthScope defines the scope for the external authentication hook.
  398. // - 0 means all supported authentication scopes, the external hook will be executed for password,
  399. // public key, keyboard interactive authentication and TLS certificates
  400. // - 1 means passwords only
  401. // - 2 means public keys only
  402. // - 4 means keyboard interactive only
  403. // - 8 means TLS certificates only
  404. // you can combine the scopes, for example 3 means password and public key, 5 password and keyboard
  405. // interactive and so on
  406. ExternalAuthScope int `json:"external_auth_scope" mapstructure:"external_auth_scope"`
  407. // Absolute path to an external program or an HTTP URL to invoke just before the user login.
  408. // This program/URL allows to modify or create the user trying to login.
  409. // It is useful if you have users with dynamic fields to update just before the login.
  410. // Please note that if you want to create a new user, the pre-login hook response must
  411. // include all the mandatory user fields.
  412. //
  413. // The pre-login hook must finish within 30 seconds.
  414. //
  415. // If an error happens while executing the "PreLoginHook" then login will be denied.
  416. // PreLoginHook and ExternalAuthHook are mutally exclusive.
  417. // Leave empty to disable.
  418. PreLoginHook string `json:"pre_login_hook" mapstructure:"pre_login_hook"`
  419. // Absolute path to an external program or an HTTP URL to invoke after the user login.
  420. // Based on the configured scope you can choose if notify failed or successful logins
  421. // or both
  422. PostLoginHook string `json:"post_login_hook" mapstructure:"post_login_hook"`
  423. // PostLoginScope defines the scope for the post-login hook.
  424. // - 0 means notify both failed and successful logins
  425. // - 1 means notify failed logins
  426. // - 2 means notify successful logins
  427. PostLoginScope int `json:"post_login_scope" mapstructure:"post_login_scope"`
  428. // Absolute path to an external program or an HTTP URL to invoke just before password
  429. // authentication. This hook allows you to externally check the provided password,
  430. // its main use case is to allow to easily support things like password+OTP for protocols
  431. // without keyboard interactive support such as FTP and WebDAV. You can ask your users
  432. // to login using a string consisting of a fixed password and a One Time Token, you
  433. // can verify the token inside the hook and ask to SFTPGo to verify the fixed part.
  434. CheckPasswordHook string `json:"check_password_hook" mapstructure:"check_password_hook"`
  435. // CheckPasswordScope defines the scope for the check password hook.
  436. // - 0 means all protocols
  437. // - 1 means SSH
  438. // - 2 means FTP
  439. // - 4 means WebDAV
  440. // you can combine the scopes, for example 6 means FTP and WebDAV
  441. CheckPasswordScope int `json:"check_password_scope" mapstructure:"check_password_scope"`
  442. // Defines how the database will be initialized/updated:
  443. // - 0 means automatically
  444. // - 1 means manually using the initprovider sub-command
  445. UpdateMode int `json:"update_mode" mapstructure:"update_mode"`
  446. // PasswordHashing defines the configuration for password hashing
  447. PasswordHashing PasswordHashing `json:"password_hashing" mapstructure:"password_hashing"`
  448. // PasswordValidation defines the password validation rules
  449. PasswordValidation PasswordValidation `json:"password_validation" mapstructure:"password_validation"`
  450. // Verifying argon2 passwords has a high memory and computational cost,
  451. // by enabling, in memory, password caching you reduce this cost.
  452. PasswordCaching bool `json:"password_caching" mapstructure:"password_caching"`
  453. // DelayedQuotaUpdate defines the number of seconds to accumulate quota updates.
  454. // If there are a lot of close uploads, accumulating quota updates can save you many
  455. // queries to the data provider.
  456. // If you want to track quotas, a scheduled quota update is recommended in any case, the stored
  457. // quota size may be incorrect for several reasons, such as an unexpected shutdown, temporary provider
  458. // failures, file copied outside of SFTPGo, and so on.
  459. // 0 means immediate quota update.
  460. DelayedQuotaUpdate int `json:"delayed_quota_update" mapstructure:"delayed_quota_update"`
  461. // If enabled, a default admin user with username "admin" and password "password" will be created
  462. // on first start.
  463. // You can also create the first admin user by using the web interface or by loading initial data.
  464. CreateDefaultAdmin bool `json:"create_default_admin" mapstructure:"create_default_admin"`
  465. // Rules for usernames and folder names:
  466. // - 0 means no rules
  467. // - 1 means you can use any UTF-8 character. The names are used in URIs for REST API and Web admin.
  468. // By default only unreserved URI characters are allowed: ALPHA / DIGIT / "-" / "." / "_" / "~".
  469. // - 2 means names are converted to lowercase before saving/matching and so case
  470. // insensitive matching is possible
  471. // - 4 means trimming trailing and leading white spaces before saving/matching
  472. // Rules can be combined, for example 3 means both converting to lowercase and allowing any UTF-8 character.
  473. // Enabling these options for existing installations could be backward incompatible, some users
  474. // could be unable to login, for example existing users with mixed cases in their usernames.
  475. // You have to ensure that all existing users respect the defined rules.
  476. NamingRules int `json:"naming_rules" mapstructure:"naming_rules"`
  477. // If the data provider is shared across multiple SFTPGo instances, set this parameter to 1.
  478. // MySQL, PostgreSQL and CockroachDB can be shared, this setting is ignored for other data
  479. // providers. For shared data providers, SFTPGo periodically reloads the latest updated users,
  480. // based on the "updated_at" field, and updates its internal caches if users are updated from
  481. // a different instance. This check, if enabled, is executed every 10 minutes.
  482. // For shared data providers, active transfers are persisted in the database and thus
  483. // quota checks between ongoing transfers will work cross multiple instances
  484. IsShared int `json:"is_shared" mapstructure:"is_shared"`
  485. // Node defines the configuration for this cluster node.
  486. // Ignored if the provider is not shared/shareable
  487. Node NodeConfig `json:"node" mapstructure:"node"`
  488. // Path to the backup directory. This can be an absolute path or a path relative to the config dir
  489. BackupsPath string `json:"backups_path" mapstructure:"backups_path"`
  490. }
  491. // GetShared returns the provider share mode.
  492. // This method is called before the provider is initialized
  493. func (c *Config) GetShared() int {
  494. if !slices.Contains(sharedProviders, c.Driver) {
  495. return 0
  496. }
  497. return c.IsShared
  498. }
  499. func (c *Config) convertName(name string) string {
  500. if c.NamingRules <= 1 {
  501. return name
  502. }
  503. if c.NamingRules&2 != 0 {
  504. name = strings.ToLower(name)
  505. }
  506. if c.NamingRules&4 != 0 {
  507. name = strings.TrimSpace(name)
  508. }
  509. return name
  510. }
  511. // IsDefenderSupported returns true if the configured provider supports the defender
  512. func (c *Config) IsDefenderSupported() bool {
  513. switch c.Driver {
  514. case MySQLDataProviderName, PGSQLDataProviderName, CockroachDataProviderName:
  515. return true
  516. default:
  517. return false
  518. }
  519. }
  520. func (c *Config) requireCustomTLSForMySQL() bool {
  521. if config.DisableSNI {
  522. return config.SSLMode != 0
  523. }
  524. if config.RootCert != "" && util.IsFileInputValid(config.RootCert) {
  525. return config.SSLMode != 0
  526. }
  527. if config.ClientCert != "" && config.ClientKey != "" && util.IsFileInputValid(config.ClientCert) &&
  528. util.IsFileInputValid(config.ClientKey) {
  529. return config.SSLMode != 0
  530. }
  531. return false
  532. }
  533. func (c *Config) doBackup() (string, error) {
  534. now := time.Now().UTC()
  535. outputFile := filepath.Join(c.BackupsPath, fmt.Sprintf("backup_%s_%d.json", now.Weekday(), now.Hour()))
  536. providerLog(logger.LevelDebug, "starting backup to file %q", outputFile)
  537. err := os.MkdirAll(filepath.Dir(outputFile), 0700)
  538. if err != nil {
  539. providerLog(logger.LevelError, "unable to create backup dir %q: %v", outputFile, err)
  540. return outputFile, fmt.Errorf("unable to create backup dir: %w", err)
  541. }
  542. backup, err := DumpData(nil)
  543. if err != nil {
  544. providerLog(logger.LevelError, "unable to execute backup: %v", err)
  545. return outputFile, fmt.Errorf("unable to dump backup data: %w", err)
  546. }
  547. dump, err := json.Marshal(backup)
  548. if err != nil {
  549. providerLog(logger.LevelError, "unable to marshal backup as JSON: %v", err)
  550. return outputFile, fmt.Errorf("unable to marshal backup data as JSON: %w", err)
  551. }
  552. err = os.WriteFile(outputFile, dump, 0600)
  553. if err != nil {
  554. providerLog(logger.LevelError, "unable to save backup: %v", err)
  555. return outputFile, fmt.Errorf("unable to save backup: %w", err)
  556. }
  557. providerLog(logger.LevelDebug, "backup saved to %q", outputFile)
  558. return outputFile, nil
  559. }
  560. // SetTZ sets the configured timezone.
  561. func SetTZ(val string) {
  562. tz = val
  563. }
  564. // UseLocalTime returns true if local time should be used instead of UTC.
  565. func UseLocalTime() bool {
  566. return tz == "local"
  567. }
  568. // ExecuteBackup executes a backup
  569. func ExecuteBackup() (string, error) {
  570. return config.doBackup()
  571. }
  572. // ConvertName converts the given name based on the configured rules
  573. func ConvertName(name string) string {
  574. return config.convertName(name)
  575. }
  576. // ActiveTransfer defines an active protocol transfer
  577. type ActiveTransfer struct {
  578. ID int64
  579. Type int
  580. ConnID string
  581. Username string
  582. FolderName string
  583. IP string
  584. TruncatedSize int64
  585. CurrentULSize int64
  586. CurrentDLSize int64
  587. CreatedAt int64
  588. UpdatedAt int64
  589. }
  590. // TransferQuota stores the allowed transfer quota fields
  591. type TransferQuota struct {
  592. ULSize int64
  593. DLSize int64
  594. TotalSize int64
  595. AllowedULSize int64
  596. AllowedDLSize int64
  597. AllowedTotalSize int64
  598. }
  599. // HasSizeLimits returns true if any size limit is set
  600. func (q *TransferQuota) HasSizeLimits() bool {
  601. return q.AllowedDLSize > 0 || q.AllowedULSize > 0 || q.AllowedTotalSize > 0
  602. }
  603. // HasUploadSpace returns true if there is transfer upload space available
  604. func (q *TransferQuota) HasUploadSpace() bool {
  605. if q.TotalSize <= 0 && q.ULSize <= 0 {
  606. return true
  607. }
  608. if q.TotalSize > 0 {
  609. return q.AllowedTotalSize > 0
  610. }
  611. return q.AllowedULSize > 0
  612. }
  613. // HasDownloadSpace returns true if there is transfer download space available
  614. func (q *TransferQuota) HasDownloadSpace() bool {
  615. if q.TotalSize <= 0 && q.DLSize <= 0 {
  616. return true
  617. }
  618. if q.TotalSize > 0 {
  619. return q.AllowedTotalSize > 0
  620. }
  621. return q.AllowedDLSize > 0
  622. }
  623. // DefenderEntry defines a defender entry
  624. type DefenderEntry struct {
  625. ID int64 `json:"-"`
  626. IP string `json:"ip"`
  627. Score int `json:"score,omitempty"`
  628. BanTime time.Time `json:"ban_time,omitempty"`
  629. }
  630. // GetID returns an unique ID for a defender entry
  631. func (d *DefenderEntry) GetID() string {
  632. return hex.EncodeToString([]byte(d.IP))
  633. }
  634. // GetBanTime returns the ban time for a defender entry as string
  635. func (d *DefenderEntry) GetBanTime() string {
  636. if d.BanTime.IsZero() {
  637. return ""
  638. }
  639. return d.BanTime.UTC().Format(time.RFC3339)
  640. }
  641. // MarshalJSON returns the JSON encoding of a DefenderEntry.
  642. func (d *DefenderEntry) MarshalJSON() ([]byte, error) {
  643. return json.Marshal(&struct {
  644. ID string `json:"id"`
  645. IP string `json:"ip"`
  646. Score int `json:"score,omitempty"`
  647. BanTime string `json:"ban_time,omitempty"`
  648. }{
  649. ID: d.GetID(),
  650. IP: d.IP,
  651. Score: d.Score,
  652. BanTime: d.GetBanTime(),
  653. })
  654. }
  655. // BackupData defines the structure for the backup/restore files
  656. type BackupData struct {
  657. Users []User `json:"users"`
  658. Groups []Group `json:"groups"`
  659. Folders []vfs.BaseVirtualFolder `json:"folders"`
  660. Admins []Admin `json:"admins"`
  661. APIKeys []APIKey `json:"api_keys"`
  662. Shares []Share `json:"shares"`
  663. EventActions []BaseEventAction `json:"event_actions"`
  664. EventRules []EventRule `json:"event_rules"`
  665. Roles []Role `json:"roles"`
  666. IPLists []IPListEntry `json:"ip_lists"`
  667. Configs *Configs `json:"configs"`
  668. Version int `json:"version"`
  669. }
  670. // HasFolder returns true if the folder with the given name is included
  671. func (d *BackupData) HasFolder(name string) bool {
  672. for _, folder := range d.Folders {
  673. if folder.Name == name {
  674. return true
  675. }
  676. }
  677. return false
  678. }
  679. type checkPasswordRequest struct {
  680. Username string `json:"username"`
  681. IP string `json:"ip"`
  682. Password string `json:"password"`
  683. Protocol string `json:"protocol"`
  684. }
  685. type checkPasswordResponse struct {
  686. // 0 KO, 1 OK, 2 partial success, -1 not executed
  687. Status int `json:"status"`
  688. // for status = 2 this is the password to check against the one stored
  689. // inside the SFTPGo data provider
  690. ToVerify string `json:"to_verify"`
  691. }
  692. // GetQuotaTracking returns the configured mode for user's quota tracking
  693. func GetQuotaTracking() int {
  694. return config.TrackQuota
  695. }
  696. // HasUsersBaseDir returns true if users base dir is set
  697. func HasUsersBaseDir() bool {
  698. return config.UsersBaseDir != ""
  699. }
  700. // Provider defines the interface that data providers must implement.
  701. type Provider interface {
  702. validateUserAndPass(username, password, ip, protocol string) (User, error)
  703. validateUserAndPubKey(username string, pubKey []byte, isSSHCert bool) (User, string, error)
  704. validateUserAndTLSCert(username, protocol string, tlsCert *x509.Certificate) (User, error)
  705. updateQuota(username string, filesAdd int, sizeAdd int64, reset bool) error
  706. updateTransferQuota(username string, uploadSize, downloadSize int64, reset bool) error
  707. getUsedQuota(username string) (int, int64, int64, int64, error)
  708. userExists(username, role string) (User, error)
  709. addUser(user *User) error
  710. updateUser(user *User) error
  711. deleteUser(user User, softDelete bool) error
  712. updateUserPassword(username, password string) error // used internally when converting passwords from other hash
  713. getUsers(limit int, offset int, order, role string) ([]User, error)
  714. dumpUsers() ([]User, error)
  715. getRecentlyUpdatedUsers(after int64) ([]User, error)
  716. getUsersForQuotaCheck(toFetch map[string]bool) ([]User, error)
  717. updateLastLogin(username string) error
  718. updateAdminLastLogin(username string) error
  719. setUpdatedAt(username string)
  720. getAdminSignature(username string) (string, error)
  721. getUserSignature(username string) (string, error)
  722. getFolders(limit, offset int, order string, minimal bool) ([]vfs.BaseVirtualFolder, error)
  723. getFolderByName(name string) (vfs.BaseVirtualFolder, error)
  724. addFolder(folder *vfs.BaseVirtualFolder) error
  725. updateFolder(folder *vfs.BaseVirtualFolder) error
  726. deleteFolder(folder vfs.BaseVirtualFolder) error
  727. updateFolderQuota(name string, filesAdd int, sizeAdd int64, reset bool) error
  728. getUsedFolderQuota(name string) (int, int64, error)
  729. dumpFolders() ([]vfs.BaseVirtualFolder, error)
  730. getGroups(limit, offset int, order string, minimal bool) ([]Group, error)
  731. getGroupsWithNames(names []string) ([]Group, error)
  732. getUsersInGroups(names []string) ([]string, error)
  733. groupExists(name string) (Group, error)
  734. addGroup(group *Group) error
  735. updateGroup(group *Group) error
  736. deleteGroup(group Group) error
  737. dumpGroups() ([]Group, error)
  738. adminExists(username string) (Admin, error)
  739. addAdmin(admin *Admin) error
  740. updateAdmin(admin *Admin) error
  741. deleteAdmin(admin Admin) error
  742. getAdmins(limit int, offset int, order string) ([]Admin, error)
  743. dumpAdmins() ([]Admin, error)
  744. validateAdminAndPass(username, password, ip string) (Admin, error)
  745. apiKeyExists(keyID string) (APIKey, error)
  746. addAPIKey(apiKey *APIKey) error
  747. updateAPIKey(apiKey *APIKey) error
  748. deleteAPIKey(apiKey APIKey) error
  749. getAPIKeys(limit int, offset int, order string) ([]APIKey, error)
  750. dumpAPIKeys() ([]APIKey, error)
  751. updateAPIKeyLastUse(keyID string) error
  752. shareExists(shareID, username string) (Share, error)
  753. addShare(share *Share) error
  754. updateShare(share *Share) error
  755. deleteShare(share Share) error
  756. getShares(limit int, offset int, order, username string) ([]Share, error)
  757. dumpShares() ([]Share, error)
  758. updateShareLastUse(shareID string, numTokens int) error
  759. getDefenderHosts(from int64, limit int) ([]DefenderEntry, error)
  760. getDefenderHostByIP(ip string, from int64) (DefenderEntry, error)
  761. isDefenderHostBanned(ip string) (DefenderEntry, error)
  762. updateDefenderBanTime(ip string, minutes int) error
  763. deleteDefenderHost(ip string) error
  764. addDefenderEvent(ip string, score int) error
  765. setDefenderBanTime(ip string, banTime int64) error
  766. cleanupDefender(from int64) error
  767. addActiveTransfer(transfer ActiveTransfer) error
  768. updateActiveTransferSizes(ulSize, dlSize, transferID int64, connectionID string) error
  769. removeActiveTransfer(transferID int64, connectionID string) error
  770. cleanupActiveTransfers(before time.Time) error
  771. getActiveTransfers(from time.Time) ([]ActiveTransfer, error)
  772. addSharedSession(session Session) error
  773. deleteSharedSession(key string, sessionType SessionType) error
  774. getSharedSession(key string, sessionType SessionType) (Session, error)
  775. cleanupSharedSessions(sessionType SessionType, before int64) error
  776. getEventActions(limit, offset int, order string, minimal bool) ([]BaseEventAction, error)
  777. dumpEventActions() ([]BaseEventAction, error)
  778. eventActionExists(name string) (BaseEventAction, error)
  779. addEventAction(action *BaseEventAction) error
  780. updateEventAction(action *BaseEventAction) error
  781. deleteEventAction(action BaseEventAction) error
  782. getEventRules(limit, offset int, order string) ([]EventRule, error)
  783. dumpEventRules() ([]EventRule, error)
  784. getRecentlyUpdatedRules(after int64) ([]EventRule, error)
  785. eventRuleExists(name string) (EventRule, error)
  786. addEventRule(rule *EventRule) error
  787. updateEventRule(rule *EventRule) error
  788. deleteEventRule(rule EventRule, softDelete bool) error
  789. getTaskByName(name string) (Task, error)
  790. addTask(name string) error
  791. updateTask(name string, version int64) error
  792. updateTaskTimestamp(name string) error
  793. setFirstDownloadTimestamp(username string) error
  794. setFirstUploadTimestamp(username string) error
  795. addNode() error
  796. getNodeByName(name string) (Node, error)
  797. getNodes() ([]Node, error)
  798. updateNodeTimestamp() error
  799. cleanupNodes() error
  800. roleExists(name string) (Role, error)
  801. addRole(role *Role) error
  802. updateRole(role *Role) error
  803. deleteRole(role Role) error
  804. getRoles(limit int, offset int, order string, minimal bool) ([]Role, error)
  805. dumpRoles() ([]Role, error)
  806. ipListEntryExists(ipOrNet string, listType IPListType) (IPListEntry, error)
  807. addIPListEntry(entry *IPListEntry) error
  808. updateIPListEntry(entry *IPListEntry) error
  809. deleteIPListEntry(entry IPListEntry, softDelete bool) error
  810. getIPListEntries(listType IPListType, filter, from, order string, limit int) ([]IPListEntry, error)
  811. getRecentlyUpdatedIPListEntries(after int64) ([]IPListEntry, error)
  812. dumpIPListEntries() ([]IPListEntry, error)
  813. countIPListEntries(listType IPListType) (int64, error)
  814. getListEntriesForIP(ip string, listType IPListType) ([]IPListEntry, error)
  815. getConfigs() (Configs, error)
  816. setConfigs(configs *Configs) error
  817. checkAvailability() error
  818. close() error
  819. reloadConfig() error
  820. initializeDatabase() error
  821. migrateDatabase() error
  822. revertDatabase(targetVersion int) error
  823. resetDatabase() error
  824. }
  825. // SetAllowSelfConnections sets the desired behaviour for self connections
  826. func SetAllowSelfConnections(value int) {
  827. allowSelfConnections = value
  828. }
  829. // SetTempPath sets the path for temporary files
  830. func SetTempPath(fsPath string) {
  831. tempPath = fsPath
  832. }
  833. func checkSharedMode() {
  834. if !slices.Contains(sharedProviders, config.Driver) {
  835. config.IsShared = 0
  836. }
  837. }
  838. // Initialize the data provider.
  839. // An error is returned if the configured driver is invalid or if the data provider cannot be initialized
  840. func Initialize(cnf Config, basePath string, checkAdmins bool) error {
  841. config = cnf
  842. checkSharedMode()
  843. config.Actions.ExecuteOn = util.RemoveDuplicates(config.Actions.ExecuteOn, true)
  844. config.Actions.ExecuteFor = util.RemoveDuplicates(config.Actions.ExecuteFor, true)
  845. cnf.BackupsPath = getConfigPath(cnf.BackupsPath, basePath)
  846. if cnf.BackupsPath == "" {
  847. return fmt.Errorf("required directory is invalid, backup path %q", cnf.BackupsPath)
  848. }
  849. absoluteBackupPath, err := util.GetAbsolutePath(cnf.BackupsPath)
  850. if err != nil {
  851. return fmt.Errorf("unable to get absolute backup path: %w", err)
  852. }
  853. config.BackupsPath = absoluteBackupPath
  854. if err := initializeHashingAlgo(&cnf); err != nil {
  855. return err
  856. }
  857. if err := validateHooks(); err != nil {
  858. return err
  859. }
  860. if err := createProvider(basePath); err != nil {
  861. return err
  862. }
  863. if err := checkDatabase(checkAdmins); err != nil {
  864. return err
  865. }
  866. admins, err := provider.getAdmins(1, 0, OrderASC)
  867. if err != nil {
  868. return err
  869. }
  870. isAdminCreated.Store(len(admins) > 0)
  871. if err := config.Node.validate(); err != nil {
  872. return err
  873. }
  874. delayedQuotaUpdater.start()
  875. if currentNode != nil {
  876. config.BackupsPath = filepath.Join(config.BackupsPath, currentNode.Name)
  877. }
  878. providerLog(logger.LevelDebug, "absolute backup path %q", config.BackupsPath)
  879. return startScheduler()
  880. }
  881. func checkDatabase(checkAdmins bool) error {
  882. if config.UpdateMode == 0 {
  883. err := provider.initializeDatabase()
  884. if err != nil && err != ErrNoInitRequired {
  885. logger.WarnToConsole("unable to initialize data provider: %v", err)
  886. providerLog(logger.LevelError, "unable to initialize data provider: %v", err)
  887. return err
  888. }
  889. if err == nil {
  890. logger.DebugToConsole("data provider successfully initialized")
  891. providerLog(logger.LevelInfo, "data provider successfully initialized")
  892. }
  893. err = provider.migrateDatabase()
  894. if err != nil && err != ErrNoInitRequired {
  895. providerLog(logger.LevelError, "database migration error: %v", err)
  896. return err
  897. }
  898. if checkAdmins && config.CreateDefaultAdmin {
  899. err = checkDefaultAdmin()
  900. if err != nil {
  901. providerLog(logger.LevelError, "erro checking the default admin: %v", err)
  902. return err
  903. }
  904. }
  905. } else {
  906. providerLog(logger.LevelInfo, "database initialization/migration skipped, manual mode is configured")
  907. }
  908. return nil
  909. }
  910. func validateHooks() error {
  911. var hooks []string
  912. if config.PreLoginHook != "" && !strings.HasPrefix(config.PreLoginHook, "http") {
  913. hooks = append(hooks, config.PreLoginHook)
  914. }
  915. if config.ExternalAuthHook != "" && !strings.HasPrefix(config.ExternalAuthHook, "http") {
  916. hooks = append(hooks, config.ExternalAuthHook)
  917. }
  918. if config.PostLoginHook != "" && !strings.HasPrefix(config.PostLoginHook, "http") {
  919. hooks = append(hooks, config.PostLoginHook)
  920. }
  921. if config.CheckPasswordHook != "" && !strings.HasPrefix(config.CheckPasswordHook, "http") {
  922. hooks = append(hooks, config.CheckPasswordHook)
  923. }
  924. for _, hook := range hooks {
  925. if !filepath.IsAbs(hook) {
  926. return fmt.Errorf("invalid hook: %q must be an absolute path", hook)
  927. }
  928. _, err := os.Stat(hook)
  929. if err != nil {
  930. providerLog(logger.LevelError, "invalid hook: %v", err)
  931. return err
  932. }
  933. }
  934. return nil
  935. }
  936. // GetBackupsPath returns the normalized backups path
  937. func GetBackupsPath() string {
  938. return config.BackupsPath
  939. }
  940. // GetProviderFromValue returns the FilesystemProvider matching the specified value.
  941. // If no match is found LocalFilesystemProvider is returned.
  942. func GetProviderFromValue(value string) sdk.FilesystemProvider {
  943. val, err := strconv.Atoi(value)
  944. if err != nil {
  945. return sdk.LocalFilesystemProvider
  946. }
  947. result := sdk.FilesystemProvider(val)
  948. if sdk.IsProviderSupported(result) {
  949. return result
  950. }
  951. return sdk.LocalFilesystemProvider
  952. }
  953. func initializeHashingAlgo(cnf *Config) error {
  954. parallelism := cnf.PasswordHashing.Argon2Options.Parallelism
  955. if parallelism == 0 {
  956. parallelism = uint8(runtime.NumCPU())
  957. }
  958. argon2Params = &argon2id.Params{
  959. Memory: cnf.PasswordHashing.Argon2Options.Memory,
  960. Iterations: cnf.PasswordHashing.Argon2Options.Iterations,
  961. Parallelism: parallelism,
  962. SaltLength: 16,
  963. KeyLength: 32,
  964. }
  965. if config.PasswordHashing.Algo == HashingAlgoBcrypt {
  966. if config.PasswordHashing.BcryptOptions.Cost > bcrypt.MaxCost {
  967. err := fmt.Errorf("invalid bcrypt cost %v, max allowed %v", config.PasswordHashing.BcryptOptions.Cost, bcrypt.MaxCost)
  968. logger.WarnToConsole("Unable to initialize data provider: %v", err)
  969. providerLog(logger.LevelError, "Unable to initialize data provider: %v", err)
  970. return err
  971. }
  972. }
  973. return nil
  974. }
  975. func validateSQLTablesPrefix() error {
  976. initSQLTables()
  977. if config.SQLTablesPrefix != "" {
  978. for _, char := range config.SQLTablesPrefix {
  979. if !strings.Contains(sqlPrefixValidChars, strings.ToLower(string(char))) {
  980. return errors.New("invalid sql_tables_prefix only chars in range 'a..z', 'A..Z', '0-9' and '_' are allowed")
  981. }
  982. }
  983. sqlTableUsers = config.SQLTablesPrefix + sqlTableUsers
  984. sqlTableFolders = config.SQLTablesPrefix + sqlTableFolders
  985. sqlTableUsersFoldersMapping = config.SQLTablesPrefix + sqlTableUsersFoldersMapping
  986. sqlTableAdmins = config.SQLTablesPrefix + sqlTableAdmins
  987. sqlTableAPIKeys = config.SQLTablesPrefix + sqlTableAPIKeys
  988. sqlTableShares = config.SQLTablesPrefix + sqlTableShares
  989. sqlTableDefenderEvents = config.SQLTablesPrefix + sqlTableDefenderEvents
  990. sqlTableDefenderHosts = config.SQLTablesPrefix + sqlTableDefenderHosts
  991. sqlTableActiveTransfers = config.SQLTablesPrefix + sqlTableActiveTransfers
  992. sqlTableGroups = config.SQLTablesPrefix + sqlTableGroups
  993. sqlTableUsersGroupsMapping = config.SQLTablesPrefix + sqlTableUsersGroupsMapping
  994. sqlTableAdminsGroupsMapping = config.SQLTablesPrefix + sqlTableAdminsGroupsMapping
  995. sqlTableGroupsFoldersMapping = config.SQLTablesPrefix + sqlTableGroupsFoldersMapping
  996. sqlTableSharedSessions = config.SQLTablesPrefix + sqlTableSharedSessions
  997. sqlTableEventsActions = config.SQLTablesPrefix + sqlTableEventsActions
  998. sqlTableEventsRules = config.SQLTablesPrefix + sqlTableEventsRules
  999. sqlTableRulesActionsMapping = config.SQLTablesPrefix + sqlTableRulesActionsMapping
  1000. sqlTableTasks = config.SQLTablesPrefix + sqlTableTasks
  1001. sqlTableNodes = config.SQLTablesPrefix + sqlTableNodes
  1002. sqlTableRoles = config.SQLTablesPrefix + sqlTableRoles
  1003. sqlTableIPLists = config.SQLTablesPrefix + sqlTableIPLists
  1004. sqlTableConfigs = config.SQLTablesPrefix + sqlTableConfigs
  1005. sqlTableSchemaVersion = config.SQLTablesPrefix + sqlTableSchemaVersion
  1006. providerLog(logger.LevelDebug, "sql table for users %q, folders %q users folders mapping %q admins %q "+
  1007. "api keys %q shares %q defender hosts %q defender events %q transfers %q groups %q "+
  1008. "users groups mapping %q admins groups mapping %q groups folders mapping %q shared sessions %q "+
  1009. "schema version %q events actions %q events rules %q rules actions mapping %q tasks %q nodes %q roles %q"+
  1010. "ip lists %q configs %q",
  1011. sqlTableUsers, sqlTableFolders, sqlTableUsersFoldersMapping, sqlTableAdmins, sqlTableAPIKeys,
  1012. sqlTableShares, sqlTableDefenderHosts, sqlTableDefenderEvents, sqlTableActiveTransfers, sqlTableGroups,
  1013. sqlTableUsersGroupsMapping, sqlTableAdminsGroupsMapping, sqlTableGroupsFoldersMapping, sqlTableSharedSessions,
  1014. sqlTableSchemaVersion, sqlTableEventsActions, sqlTableEventsRules, sqlTableRulesActionsMapping,
  1015. sqlTableTasks, sqlTableNodes, sqlTableRoles, sqlTableIPLists, sqlTableConfigs)
  1016. }
  1017. return nil
  1018. }
  1019. func checkDefaultAdmin() error {
  1020. admins, err := provider.getAdmins(1, 0, OrderASC)
  1021. if err != nil {
  1022. return err
  1023. }
  1024. if len(admins) > 0 {
  1025. return nil
  1026. }
  1027. logger.Debug(logSender, "", "no admins found, try to create the default one")
  1028. // we need to create the default admin
  1029. admin := &Admin{}
  1030. if err := admin.setFromEnv(); err != nil {
  1031. return err
  1032. }
  1033. return provider.addAdmin(admin)
  1034. }
  1035. // InitializeDatabase creates the initial database structure
  1036. func InitializeDatabase(cnf Config, basePath string) error {
  1037. config = cnf
  1038. if err := initializeHashingAlgo(&cnf); err != nil {
  1039. return err
  1040. }
  1041. err := createProvider(basePath)
  1042. if err != nil {
  1043. return err
  1044. }
  1045. err = provider.initializeDatabase()
  1046. if err != nil && err != ErrNoInitRequired {
  1047. return err
  1048. }
  1049. return provider.migrateDatabase()
  1050. }
  1051. // RevertDatabase restores schema and/or data to a previous version
  1052. func RevertDatabase(cnf Config, basePath string, targetVersion int) error {
  1053. config = cnf
  1054. err := createProvider(basePath)
  1055. if err != nil {
  1056. return err
  1057. }
  1058. err = provider.initializeDatabase()
  1059. if err != nil && err != ErrNoInitRequired {
  1060. return err
  1061. }
  1062. return provider.revertDatabase(targetVersion)
  1063. }
  1064. // ResetDatabase restores schema and/or data to a previous version
  1065. func ResetDatabase(cnf Config, basePath string) error {
  1066. config = cnf
  1067. if err := createProvider(basePath); err != nil {
  1068. return err
  1069. }
  1070. return provider.resetDatabase()
  1071. }
  1072. // CheckAdminAndPass validates the given admin and password connecting from ip
  1073. func CheckAdminAndPass(username, password, ip string) (Admin, error) {
  1074. username = config.convertName(username)
  1075. return provider.validateAdminAndPass(username, password, ip)
  1076. }
  1077. // CheckCachedUserCredentials checks the credentials for a cached user
  1078. func CheckCachedUserCredentials(user *CachedUser, password, ip, loginMethod, protocol string, tlsCert *x509.Certificate) (*CachedUser, *User, error) {
  1079. if !user.User.skipExternalAuth() && isExternalAuthConfigured(loginMethod) {
  1080. u, _, err := CheckCompositeCredentials(user.User.Username, password, ip, loginMethod, protocol, tlsCert)
  1081. if err != nil {
  1082. return nil, nil, err
  1083. }
  1084. webDAVUsersCache.swap(&u, password)
  1085. cu, _ := webDAVUsersCache.get(u.Username)
  1086. return cu, &u, nil
  1087. }
  1088. if err := user.User.CheckLoginConditions(); err != nil {
  1089. return user, nil, err
  1090. }
  1091. if loginMethod == LoginMethodPassword && user.User.Filters.IsAnonymous {
  1092. return user, nil, nil
  1093. }
  1094. if loginMethod != LoginMethodPassword {
  1095. _, err := checkUserAndTLSCertificate(&user.User, protocol, tlsCert)
  1096. if err != nil {
  1097. return user, nil, err
  1098. }
  1099. if loginMethod == LoginMethodTLSCertificate {
  1100. if !user.User.IsLoginMethodAllowed(LoginMethodTLSCertificate, protocol) {
  1101. return user, nil, fmt.Errorf("certificate login method is not allowed for user %q", user.User.Username)
  1102. }
  1103. return user, nil, nil
  1104. }
  1105. }
  1106. if password == "" {
  1107. return user, nil, ErrInvalidCredentials
  1108. }
  1109. if user.Password != "" {
  1110. if password == user.Password {
  1111. return user, nil, nil
  1112. }
  1113. } else {
  1114. if ok, _ := isPasswordOK(&user.User, password); ok {
  1115. return user, nil, nil
  1116. }
  1117. }
  1118. return user, nil, ErrInvalidCredentials
  1119. }
  1120. // CheckCompositeCredentials checks multiple credentials.
  1121. // WebDAV users can send both a password and a TLS certificate within the same request
  1122. func CheckCompositeCredentials(username, password, ip, loginMethod, protocol string, tlsCert *x509.Certificate) (User, string, error) {
  1123. username = config.convertName(username)
  1124. if loginMethod == LoginMethodPassword {
  1125. user, err := CheckUserAndPass(username, password, ip, protocol)
  1126. return user, loginMethod, err
  1127. }
  1128. user, err := CheckUserBeforeTLSAuth(username, ip, protocol, tlsCert)
  1129. if err != nil {
  1130. return user, loginMethod, err
  1131. }
  1132. if !user.IsTLSVerificationEnabled() {
  1133. // for backward compatibility with 2.0.x we only check the password and change the login method here
  1134. // in future updates we have to return an error
  1135. user, err := CheckUserAndPass(username, password, ip, protocol)
  1136. return user, LoginMethodPassword, err
  1137. }
  1138. user, err = checkUserAndTLSCertificate(&user, protocol, tlsCert)
  1139. if err != nil {
  1140. return user, loginMethod, err
  1141. }
  1142. if loginMethod == LoginMethodTLSCertificate && !user.IsLoginMethodAllowed(LoginMethodTLSCertificate, protocol) {
  1143. return user, loginMethod, fmt.Errorf("certificate login method is not allowed for user %q", user.Username)
  1144. }
  1145. if loginMethod == LoginMethodTLSCertificateAndPwd {
  1146. if plugin.Handler.HasAuthScope(plugin.AuthScopePassword) {
  1147. user, err = doPluginAuth(username, password, nil, ip, protocol, nil, plugin.AuthScopePassword)
  1148. } else if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&1 != 0) {
  1149. user, err = doExternalAuth(username, password, nil, "", ip, protocol, nil)
  1150. } else if config.PreLoginHook != "" {
  1151. user, err = executePreLoginHook(username, LoginMethodPassword, ip, protocol, nil)
  1152. }
  1153. if err != nil {
  1154. return user, loginMethod, err
  1155. }
  1156. user, err = checkUserAndPass(&user, password, ip, protocol)
  1157. }
  1158. return user, loginMethod, err
  1159. }
  1160. // CheckUserBeforeTLSAuth checks if a user exits before trying mutual TLS
  1161. func CheckUserBeforeTLSAuth(username, ip, protocol string, tlsCert *x509.Certificate) (User, error) {
  1162. username = config.convertName(username)
  1163. if plugin.Handler.HasAuthScope(plugin.AuthScopeTLSCertificate) {
  1164. user, err := doPluginAuth(username, "", nil, ip, protocol, tlsCert, plugin.AuthScopeTLSCertificate)
  1165. if err != nil {
  1166. return user, err
  1167. }
  1168. err = user.LoadAndApplyGroupSettings()
  1169. return user, err
  1170. }
  1171. if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&8 != 0) {
  1172. user, err := doExternalAuth(username, "", nil, "", ip, protocol, tlsCert)
  1173. if err != nil {
  1174. return user, err
  1175. }
  1176. err = user.LoadAndApplyGroupSettings()
  1177. return user, err
  1178. }
  1179. if config.PreLoginHook != "" {
  1180. user, err := executePreLoginHook(username, LoginMethodTLSCertificate, ip, protocol, nil)
  1181. if err != nil {
  1182. return user, err
  1183. }
  1184. err = user.LoadAndApplyGroupSettings()
  1185. return user, err
  1186. }
  1187. user, err := UserExists(username, "")
  1188. if err != nil {
  1189. return user, err
  1190. }
  1191. err = user.LoadAndApplyGroupSettings()
  1192. return user, err
  1193. }
  1194. // CheckUserAndTLSCert returns the SFTPGo user with the given username and check if the
  1195. // given TLS certificate allow authentication without password
  1196. func CheckUserAndTLSCert(username, ip, protocol string, tlsCert *x509.Certificate) (User, error) {
  1197. username = config.convertName(username)
  1198. if plugin.Handler.HasAuthScope(plugin.AuthScopeTLSCertificate) {
  1199. user, err := doPluginAuth(username, "", nil, ip, protocol, tlsCert, plugin.AuthScopeTLSCertificate)
  1200. if err != nil {
  1201. return user, err
  1202. }
  1203. return checkUserAndTLSCertificate(&user, protocol, tlsCert)
  1204. }
  1205. if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&8 != 0) {
  1206. user, err := doExternalAuth(username, "", nil, "", ip, protocol, tlsCert)
  1207. if err != nil {
  1208. return user, err
  1209. }
  1210. return checkUserAndTLSCertificate(&user, protocol, tlsCert)
  1211. }
  1212. if config.PreLoginHook != "" {
  1213. user, err := executePreLoginHook(username, LoginMethodTLSCertificate, ip, protocol, nil)
  1214. if err != nil {
  1215. return user, err
  1216. }
  1217. return checkUserAndTLSCertificate(&user, protocol, tlsCert)
  1218. }
  1219. return provider.validateUserAndTLSCert(username, protocol, tlsCert)
  1220. }
  1221. // CheckUserAndPass retrieves the SFTPGo user with the given username and password if a match is found or an error
  1222. func CheckUserAndPass(username, password, ip, protocol string) (User, error) {
  1223. username = config.convertName(username)
  1224. if plugin.Handler.HasAuthScope(plugin.AuthScopePassword) {
  1225. user, err := doPluginAuth(username, password, nil, ip, protocol, nil, plugin.AuthScopePassword)
  1226. if err != nil {
  1227. return user, err
  1228. }
  1229. return checkUserAndPass(&user, password, ip, protocol)
  1230. }
  1231. if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&1 != 0) {
  1232. user, err := doExternalAuth(username, password, nil, "", ip, protocol, nil)
  1233. if err != nil {
  1234. return user, err
  1235. }
  1236. return checkUserAndPass(&user, password, ip, protocol)
  1237. }
  1238. if config.PreLoginHook != "" {
  1239. user, err := executePreLoginHook(username, LoginMethodPassword, ip, protocol, nil)
  1240. if err != nil {
  1241. return user, err
  1242. }
  1243. return checkUserAndPass(&user, password, ip, protocol)
  1244. }
  1245. return provider.validateUserAndPass(username, password, ip, protocol)
  1246. }
  1247. // CheckUserAndPubKey retrieves the SFTP user with the given username and public key if a match is found or an error
  1248. func CheckUserAndPubKey(username string, pubKey []byte, ip, protocol string, isSSHCert bool) (User, string, error) {
  1249. username = config.convertName(username)
  1250. if plugin.Handler.HasAuthScope(plugin.AuthScopePublicKey) {
  1251. user, err := doPluginAuth(username, "", pubKey, ip, protocol, nil, plugin.AuthScopePublicKey)
  1252. if err != nil {
  1253. return user, "", err
  1254. }
  1255. return checkUserAndPubKey(&user, pubKey, isSSHCert)
  1256. }
  1257. if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&2 != 0) {
  1258. user, err := doExternalAuth(username, "", pubKey, "", ip, protocol, nil)
  1259. if err != nil {
  1260. return user, "", err
  1261. }
  1262. return checkUserAndPubKey(&user, pubKey, isSSHCert)
  1263. }
  1264. if config.PreLoginHook != "" {
  1265. user, err := executePreLoginHook(username, SSHLoginMethodPublicKey, ip, protocol, nil)
  1266. if err != nil {
  1267. return user, "", err
  1268. }
  1269. return checkUserAndPubKey(&user, pubKey, isSSHCert)
  1270. }
  1271. return provider.validateUserAndPubKey(username, pubKey, isSSHCert)
  1272. }
  1273. // CheckKeyboardInteractiveAuth checks the keyboard interactive authentication and returns
  1274. // the authenticated user or an error
  1275. func CheckKeyboardInteractiveAuth(username, authHook string, client ssh.KeyboardInteractiveChallenge,
  1276. ip, protocol string, isPartialAuth bool,
  1277. ) (User, error) {
  1278. var user User
  1279. var err error
  1280. username = config.convertName(username)
  1281. if plugin.Handler.HasAuthScope(plugin.AuthScopeKeyboardInteractive) {
  1282. user, err = doPluginAuth(username, "", nil, ip, protocol, nil, plugin.AuthScopeKeyboardInteractive)
  1283. } else if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&4 != 0) {
  1284. user, err = doExternalAuth(username, "", nil, "1", ip, protocol, nil)
  1285. } else if config.PreLoginHook != "" {
  1286. user, err = executePreLoginHook(username, SSHLoginMethodKeyboardInteractive, ip, protocol, nil)
  1287. } else {
  1288. user, err = provider.userExists(username, "")
  1289. }
  1290. if err != nil {
  1291. return user, err
  1292. }
  1293. return doKeyboardInteractiveAuth(&user, authHook, client, ip, protocol, isPartialAuth)
  1294. }
  1295. // GetFTPPreAuthUser returns the SFTPGo user with the specified username
  1296. // after receiving the FTP "USER" command.
  1297. // If a pre-login hook is defined it will be executed so the SFTPGo user
  1298. // can be created if it does not exist
  1299. func GetFTPPreAuthUser(username, ip string) (User, error) {
  1300. var user User
  1301. var err error
  1302. if config.PreLoginHook != "" {
  1303. user, err = executePreLoginHook(username, "", ip, protocolFTP, nil)
  1304. } else {
  1305. user, err = UserExists(username, "")
  1306. }
  1307. if err != nil {
  1308. return user, err
  1309. }
  1310. err = user.LoadAndApplyGroupSettings()
  1311. return user, err
  1312. }
  1313. // GetUserAfterIDPAuth returns the SFTPGo user with the specified username
  1314. // after a successful authentication with an external identity provider.
  1315. // If a pre-login hook is defined it will be executed so the SFTPGo user
  1316. // can be created if it does not exist
  1317. func GetUserAfterIDPAuth(username, ip, protocol string, oidcTokenFields *map[string]any) (User, error) {
  1318. var user User
  1319. var err error
  1320. if config.PreLoginHook != "" {
  1321. user, err = executePreLoginHook(username, LoginMethodIDP, ip, protocol, oidcTokenFields)
  1322. user.Filters.RequirePasswordChange = false
  1323. } else {
  1324. user, err = UserExists(username, "")
  1325. }
  1326. if err != nil {
  1327. return user, err
  1328. }
  1329. err = user.LoadAndApplyGroupSettings()
  1330. return user, err
  1331. }
  1332. // GetDefenderHosts returns hosts that are banned or for which some violations have been detected
  1333. func GetDefenderHosts(from int64, limit int) ([]DefenderEntry, error) {
  1334. return provider.getDefenderHosts(from, limit)
  1335. }
  1336. // GetDefenderHostByIP returns a defender host by ip, if any
  1337. func GetDefenderHostByIP(ip string, from int64) (DefenderEntry, error) {
  1338. return provider.getDefenderHostByIP(ip, from)
  1339. }
  1340. // IsDefenderHostBanned returns a defender entry and no error if the specified host is banned
  1341. func IsDefenderHostBanned(ip string) (DefenderEntry, error) {
  1342. return provider.isDefenderHostBanned(ip)
  1343. }
  1344. // UpdateDefenderBanTime increments ban time for the specified ip
  1345. func UpdateDefenderBanTime(ip string, minutes int) error {
  1346. return provider.updateDefenderBanTime(ip, minutes)
  1347. }
  1348. // DeleteDefenderHost removes the specified IP from the defender lists
  1349. func DeleteDefenderHost(ip string) error {
  1350. return provider.deleteDefenderHost(ip)
  1351. }
  1352. // AddDefenderEvent adds an event for the given IP with the given score
  1353. // and returns the host with the updated score
  1354. func AddDefenderEvent(ip string, score int, from int64) (DefenderEntry, error) {
  1355. if err := provider.addDefenderEvent(ip, score); err != nil {
  1356. return DefenderEntry{}, err
  1357. }
  1358. return provider.getDefenderHostByIP(ip, from)
  1359. }
  1360. // SetDefenderBanTime sets the ban time for the specified IP
  1361. func SetDefenderBanTime(ip string, banTime int64) error {
  1362. return provider.setDefenderBanTime(ip, banTime)
  1363. }
  1364. // CleanupDefender removes events and hosts older than "from" from the data provider
  1365. func CleanupDefender(from int64) error {
  1366. return provider.cleanupDefender(from)
  1367. }
  1368. // UpdateShareLastUse updates the LastUseAt and UsedTokens for the given share
  1369. func UpdateShareLastUse(share *Share, numTokens int) error {
  1370. return provider.updateShareLastUse(share.ShareID, numTokens)
  1371. }
  1372. // UpdateAPIKeyLastUse updates the LastUseAt field for the given API key
  1373. func UpdateAPIKeyLastUse(apiKey *APIKey) error {
  1374. lastUse := util.GetTimeFromMsecSinceEpoch(apiKey.LastUseAt)
  1375. diff := -time.Until(lastUse)
  1376. if diff < 0 || diff > lastLoginMinDelay {
  1377. return provider.updateAPIKeyLastUse(apiKey.KeyID)
  1378. }
  1379. return nil
  1380. }
  1381. // UpdateLastLogin updates the last login field for the given SFTPGo user
  1382. func UpdateLastLogin(user *User) {
  1383. delay := lastLoginMinDelay
  1384. if user.Filters.ExternalAuthCacheTime > 0 {
  1385. delay = time.Duration(user.Filters.ExternalAuthCacheTime) * time.Second
  1386. }
  1387. if user.LastLogin <= user.UpdatedAt || !isLastActivityRecent(user.LastLogin, delay) {
  1388. err := provider.updateLastLogin(user.Username)
  1389. if err == nil {
  1390. webDAVUsersCache.updateLastLogin(user.Username)
  1391. }
  1392. }
  1393. }
  1394. // UpdateAdminLastLogin updates the last login field for the given SFTPGo admin
  1395. func UpdateAdminLastLogin(admin *Admin) {
  1396. if !isLastActivityRecent(admin.LastLogin, lastLoginMinDelay) {
  1397. provider.updateAdminLastLogin(admin.Username) //nolint:errcheck
  1398. }
  1399. }
  1400. // UpdateUserQuota updates the quota for the given SFTPGo user adding filesAdd and sizeAdd.
  1401. // If reset is true filesAdd and sizeAdd indicates the total files and the total size instead of the difference.
  1402. func UpdateUserQuota(user *User, filesAdd int, sizeAdd int64, reset bool) error {
  1403. if config.TrackQuota == 0 {
  1404. return util.NewMethodDisabledError(trackQuotaDisabledError)
  1405. } else if config.TrackQuota == 2 && !reset && !user.HasQuotaRestrictions() {
  1406. return nil
  1407. }
  1408. if filesAdd == 0 && sizeAdd == 0 && !reset {
  1409. return nil
  1410. }
  1411. if config.DelayedQuotaUpdate == 0 || reset {
  1412. if reset {
  1413. delayedQuotaUpdater.resetUserQuota(user.Username)
  1414. }
  1415. return provider.updateQuota(user.Username, filesAdd, sizeAdd, reset)
  1416. }
  1417. delayedQuotaUpdater.updateUserQuota(user.Username, filesAdd, sizeAdd)
  1418. return nil
  1419. }
  1420. // UpdateUserFolderQuota updates the quota for the given user and virtual folder.
  1421. func UpdateUserFolderQuota(folder *vfs.VirtualFolder, user *User, filesAdd int, sizeAdd int64, reset bool) {
  1422. if folder.IsIncludedInUserQuota() {
  1423. UpdateUserQuota(user, filesAdd, sizeAdd, reset) //nolint:errcheck
  1424. return
  1425. }
  1426. UpdateVirtualFolderQuota(&folder.BaseVirtualFolder, filesAdd, sizeAdd, reset) //nolint:errcheck
  1427. }
  1428. // UpdateVirtualFolderQuota updates the quota for the given virtual folder adding filesAdd and sizeAdd.
  1429. // If reset is true filesAdd and sizeAdd indicates the total files and the total size instead of the difference.
  1430. func UpdateVirtualFolderQuota(vfolder *vfs.BaseVirtualFolder, filesAdd int, sizeAdd int64, reset bool) error {
  1431. if config.TrackQuota == 0 {
  1432. return util.NewMethodDisabledError(trackQuotaDisabledError)
  1433. }
  1434. if filesAdd == 0 && sizeAdd == 0 && !reset {
  1435. return nil
  1436. }
  1437. if config.DelayedQuotaUpdate == 0 || reset {
  1438. if reset {
  1439. delayedQuotaUpdater.resetFolderQuota(vfolder.Name)
  1440. }
  1441. return provider.updateFolderQuota(vfolder.Name, filesAdd, sizeAdd, reset)
  1442. }
  1443. delayedQuotaUpdater.updateFolderQuota(vfolder.Name, filesAdd, sizeAdd)
  1444. return nil
  1445. }
  1446. // UpdateUserTransferQuota updates the transfer quota for the given SFTPGo user.
  1447. // If reset is true uploadSize and downloadSize indicates the actual sizes instead of the difference.
  1448. func UpdateUserTransferQuota(user *User, uploadSize, downloadSize int64, reset bool) error {
  1449. if config.TrackQuota == 0 {
  1450. return util.NewMethodDisabledError(trackQuotaDisabledError)
  1451. } else if config.TrackQuota == 2 && !reset && !user.HasTransferQuotaRestrictions() {
  1452. return nil
  1453. }
  1454. if downloadSize == 0 && uploadSize == 0 && !reset {
  1455. return nil
  1456. }
  1457. if config.DelayedQuotaUpdate == 0 || reset {
  1458. if reset {
  1459. delayedQuotaUpdater.resetUserTransferQuota(user.Username)
  1460. }
  1461. return provider.updateTransferQuota(user.Username, uploadSize, downloadSize, reset)
  1462. }
  1463. delayedQuotaUpdater.updateUserTransferQuota(user.Username, uploadSize, downloadSize)
  1464. return nil
  1465. }
  1466. // UpdateUserTransferTimestamps updates the first download/upload fields if unset
  1467. func UpdateUserTransferTimestamps(username string, isUpload bool) error {
  1468. if isUpload {
  1469. err := provider.setFirstUploadTimestamp(username)
  1470. if err != nil {
  1471. providerLog(logger.LevelWarn, "unable to set first upload: %v", err)
  1472. }
  1473. return err
  1474. }
  1475. err := provider.setFirstDownloadTimestamp(username)
  1476. if err != nil {
  1477. providerLog(logger.LevelWarn, "unable to set first download: %v", err)
  1478. }
  1479. return err
  1480. }
  1481. // GetUsedQuota returns the used quota for the given SFTPGo user.
  1482. func GetUsedQuota(username string) (int, int64, int64, int64, error) {
  1483. if config.TrackQuota == 0 {
  1484. return 0, 0, 0, 0, util.NewMethodDisabledError(trackQuotaDisabledError)
  1485. }
  1486. files, size, ulTransferSize, dlTransferSize, err := provider.getUsedQuota(username)
  1487. if err != nil {
  1488. return files, size, ulTransferSize, dlTransferSize, err
  1489. }
  1490. delayedFiles, delayedSize := delayedQuotaUpdater.getUserPendingQuota(username)
  1491. delayedUlTransferSize, delayedDLTransferSize := delayedQuotaUpdater.getUserPendingTransferQuota(username)
  1492. return files + delayedFiles, size + delayedSize, ulTransferSize + delayedUlTransferSize,
  1493. dlTransferSize + delayedDLTransferSize, err
  1494. }
  1495. // GetUsedVirtualFolderQuota returns the used quota for the given virtual folder.
  1496. func GetUsedVirtualFolderQuota(name string) (int, int64, error) {
  1497. if config.TrackQuota == 0 {
  1498. return 0, 0, util.NewMethodDisabledError(trackQuotaDisabledError)
  1499. }
  1500. files, size, err := provider.getUsedFolderQuota(name)
  1501. if err != nil {
  1502. return files, size, err
  1503. }
  1504. delayedFiles, delayedSize := delayedQuotaUpdater.getFolderPendingQuota(name)
  1505. return files + delayedFiles, size + delayedSize, err
  1506. }
  1507. // GetConfigs returns the configurations
  1508. func GetConfigs() (Configs, error) {
  1509. return provider.getConfigs()
  1510. }
  1511. // UpdateConfigs updates configurations
  1512. func UpdateConfigs(configs *Configs, executor, ipAddress, role string) error {
  1513. if configs == nil {
  1514. configs = &Configs{}
  1515. } else {
  1516. configs.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
  1517. }
  1518. err := provider.setConfigs(configs)
  1519. if err == nil {
  1520. executeAction(operationUpdate, executor, ipAddress, actionObjectConfigs, "configs", role, configs)
  1521. }
  1522. return err
  1523. }
  1524. // AddShare adds a new share
  1525. func AddShare(share *Share, executor, ipAddress, role string) error {
  1526. err := provider.addShare(share)
  1527. if err == nil {
  1528. executeAction(operationAdd, executor, ipAddress, actionObjectShare, share.ShareID, role, share)
  1529. }
  1530. return err
  1531. }
  1532. // UpdateShare updates an existing share
  1533. func UpdateShare(share *Share, executor, ipAddress, role string) error {
  1534. err := provider.updateShare(share)
  1535. if err == nil {
  1536. executeAction(operationUpdate, executor, ipAddress, actionObjectShare, share.ShareID, role, share)
  1537. }
  1538. return err
  1539. }
  1540. // DeleteShare deletes an existing share
  1541. func DeleteShare(shareID string, executor, ipAddress, role string) error {
  1542. share, err := provider.shareExists(shareID, executor)
  1543. if err != nil {
  1544. return err
  1545. }
  1546. err = provider.deleteShare(share)
  1547. if err == nil {
  1548. executeAction(operationDelete, executor, ipAddress, actionObjectShare, shareID, role, &share)
  1549. }
  1550. return err
  1551. }
  1552. // ShareExists returns the share with the given ID if it exists
  1553. func ShareExists(shareID, username string) (Share, error) {
  1554. if shareID == "" {
  1555. return Share{}, util.NewRecordNotFoundError(fmt.Sprintf("Share %q does not exist", shareID))
  1556. }
  1557. return provider.shareExists(shareID, username)
  1558. }
  1559. // AddIPListEntry adds a new IP list entry
  1560. func AddIPListEntry(entry *IPListEntry, executor, ipAddress, executorRole string) error {
  1561. err := provider.addIPListEntry(entry)
  1562. if err == nil {
  1563. executeAction(operationAdd, executor, ipAddress, actionObjectIPListEntry, entry.getName(), executorRole, entry)
  1564. for _, l := range inMemoryLists {
  1565. l.addEntry(entry)
  1566. }
  1567. }
  1568. return err
  1569. }
  1570. // UpdateIPListEntry updates an existing IP list entry
  1571. func UpdateIPListEntry(entry *IPListEntry, executor, ipAddress, executorRole string) error {
  1572. err := provider.updateIPListEntry(entry)
  1573. if err == nil {
  1574. executeAction(operationUpdate, executor, ipAddress, actionObjectIPListEntry, entry.getName(), executorRole, entry)
  1575. for _, l := range inMemoryLists {
  1576. l.updateEntry(entry)
  1577. }
  1578. }
  1579. return err
  1580. }
  1581. // DeleteIPListEntry deletes an existing IP list entry
  1582. func DeleteIPListEntry(ipOrNet string, listType IPListType, executor, ipAddress, executorRole string) error {
  1583. entry, err := provider.ipListEntryExists(ipOrNet, listType)
  1584. if err != nil {
  1585. return err
  1586. }
  1587. err = provider.deleteIPListEntry(entry, config.IsShared == 1)
  1588. if err == nil {
  1589. executeAction(operationDelete, executor, ipAddress, actionObjectIPListEntry, entry.getName(), executorRole, &entry)
  1590. for _, l := range inMemoryLists {
  1591. l.removeEntry(&entry)
  1592. }
  1593. }
  1594. return err
  1595. }
  1596. // IPListEntryExists returns the IP list entry with the given IP/net and type if it exists
  1597. func IPListEntryExists(ipOrNet string, listType IPListType) (IPListEntry, error) {
  1598. return provider.ipListEntryExists(ipOrNet, listType)
  1599. }
  1600. // GetIPListEntries returns the IP list entries applying the specified criteria and search limit
  1601. func GetIPListEntries(listType IPListType, filter, from, order string, limit int) ([]IPListEntry, error) {
  1602. if !slices.Contains(supportedIPListType, listType) {
  1603. return nil, util.NewValidationError(fmt.Sprintf("invalid list type %d", listType))
  1604. }
  1605. return provider.getIPListEntries(listType, filter, from, order, limit)
  1606. }
  1607. // AddRole adds a new role
  1608. func AddRole(role *Role, executor, ipAddress, executorRole string) error {
  1609. role.Name = config.convertName(role.Name)
  1610. err := provider.addRole(role)
  1611. if err == nil {
  1612. executeAction(operationAdd, executor, ipAddress, actionObjectRole, role.Name, executorRole, role)
  1613. }
  1614. return err
  1615. }
  1616. // UpdateRole updates an existing Role
  1617. func UpdateRole(role *Role, executor, ipAddress, executorRole string) error {
  1618. err := provider.updateRole(role)
  1619. if err == nil {
  1620. executeAction(operationUpdate, executor, ipAddress, actionObjectRole, role.Name, executorRole, role)
  1621. }
  1622. return err
  1623. }
  1624. // DeleteRole deletes an existing Role
  1625. func DeleteRole(name string, executor, ipAddress, executorRole string) error {
  1626. name = config.convertName(name)
  1627. role, err := provider.roleExists(name)
  1628. if err != nil {
  1629. return err
  1630. }
  1631. if len(role.Admins) > 0 {
  1632. errorString := fmt.Sprintf("the role %q is referenced, it cannot be removed", role.Name)
  1633. return util.NewValidationError(errorString)
  1634. }
  1635. err = provider.deleteRole(role)
  1636. if err == nil {
  1637. executeAction(operationDelete, executor, ipAddress, actionObjectRole, role.Name, executorRole, &role)
  1638. for _, user := range role.Users {
  1639. provider.setUpdatedAt(user)
  1640. u, err := provider.userExists(user, "")
  1641. if err == nil {
  1642. webDAVUsersCache.swap(&u, "")
  1643. executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, u.Role, &u)
  1644. }
  1645. }
  1646. }
  1647. return err
  1648. }
  1649. // RoleExists returns the Role with the given name if it exists
  1650. func RoleExists(name string) (Role, error) {
  1651. name = config.convertName(name)
  1652. return provider.roleExists(name)
  1653. }
  1654. // AddGroup adds a new group
  1655. func AddGroup(group *Group, executor, ipAddress, role string) error {
  1656. group.Name = config.convertName(group.Name)
  1657. err := provider.addGroup(group)
  1658. if err == nil {
  1659. executeAction(operationAdd, executor, ipAddress, actionObjectGroup, group.Name, role, group)
  1660. }
  1661. return err
  1662. }
  1663. // UpdateGroup updates an existing Group
  1664. func UpdateGroup(group *Group, users []string, executor, ipAddress, role string) error {
  1665. err := provider.updateGroup(group)
  1666. if err == nil {
  1667. for _, user := range users {
  1668. provider.setUpdatedAt(user)
  1669. u, err := provider.userExists(user, "")
  1670. if err == nil {
  1671. webDAVUsersCache.swap(&u, "")
  1672. } else {
  1673. RemoveCachedWebDAVUser(user)
  1674. }
  1675. }
  1676. executeAction(operationUpdate, executor, ipAddress, actionObjectGroup, group.Name, role, group)
  1677. }
  1678. return err
  1679. }
  1680. // DeleteGroup deletes an existing Group
  1681. func DeleteGroup(name string, executor, ipAddress, role string) error {
  1682. name = config.convertName(name)
  1683. group, err := provider.groupExists(name)
  1684. if err != nil {
  1685. return err
  1686. }
  1687. if len(group.Users) > 0 {
  1688. errorString := fmt.Sprintf("the group %q is referenced, it cannot be removed", group.Name)
  1689. return util.NewValidationError(errorString)
  1690. }
  1691. err = provider.deleteGroup(group)
  1692. if err == nil {
  1693. for _, user := range group.Users {
  1694. provider.setUpdatedAt(user)
  1695. u, err := provider.userExists(user, "")
  1696. if err == nil {
  1697. executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, u.Role, &u)
  1698. }
  1699. RemoveCachedWebDAVUser(user)
  1700. }
  1701. executeAction(operationDelete, executor, ipAddress, actionObjectGroup, group.Name, role, &group)
  1702. }
  1703. return err
  1704. }
  1705. // GroupExists returns the Group with the given name if it exists
  1706. func GroupExists(name string) (Group, error) {
  1707. name = config.convertName(name)
  1708. return provider.groupExists(name)
  1709. }
  1710. // AddAPIKey adds a new API key
  1711. func AddAPIKey(apiKey *APIKey, executor, ipAddress, role string) error {
  1712. err := provider.addAPIKey(apiKey)
  1713. if err == nil {
  1714. executeAction(operationAdd, executor, ipAddress, actionObjectAPIKey, apiKey.KeyID, role, apiKey)
  1715. }
  1716. return err
  1717. }
  1718. // UpdateAPIKey updates an existing API key
  1719. func UpdateAPIKey(apiKey *APIKey, executor, ipAddress, role string) error {
  1720. err := provider.updateAPIKey(apiKey)
  1721. if err == nil {
  1722. executeAction(operationUpdate, executor, ipAddress, actionObjectAPIKey, apiKey.KeyID, role, apiKey)
  1723. }
  1724. return err
  1725. }
  1726. // DeleteAPIKey deletes an existing API key
  1727. func DeleteAPIKey(keyID string, executor, ipAddress, role string) error {
  1728. apiKey, err := provider.apiKeyExists(keyID)
  1729. if err != nil {
  1730. return err
  1731. }
  1732. err = provider.deleteAPIKey(apiKey)
  1733. if err == nil {
  1734. executeAction(operationDelete, executor, ipAddress, actionObjectAPIKey, apiKey.KeyID, role, &apiKey)
  1735. cachedAPIKeys.Remove(keyID)
  1736. }
  1737. return err
  1738. }
  1739. // APIKeyExists returns the API key with the given ID if it exists
  1740. func APIKeyExists(keyID string) (APIKey, error) {
  1741. if keyID == "" {
  1742. return APIKey{}, util.NewRecordNotFoundError(fmt.Sprintf("API key %q does not exist", keyID))
  1743. }
  1744. return provider.apiKeyExists(keyID)
  1745. }
  1746. // GetEventActions returns an array of event actions respecting limit and offset
  1747. func GetEventActions(limit, offset int, order string, minimal bool) ([]BaseEventAction, error) {
  1748. return provider.getEventActions(limit, offset, order, minimal)
  1749. }
  1750. // EventActionExists returns the event action with the given name if it exists
  1751. func EventActionExists(name string) (BaseEventAction, error) {
  1752. name = config.convertName(name)
  1753. return provider.eventActionExists(name)
  1754. }
  1755. // AddEventAction adds a new event action
  1756. func AddEventAction(action *BaseEventAction, executor, ipAddress, role string) error {
  1757. action.Name = config.convertName(action.Name)
  1758. err := provider.addEventAction(action)
  1759. if err == nil {
  1760. executeAction(operationAdd, executor, ipAddress, actionObjectEventAction, action.Name, role, action)
  1761. }
  1762. return err
  1763. }
  1764. // UpdateEventAction updates an existing event action
  1765. func UpdateEventAction(action *BaseEventAction, executor, ipAddress, role string) error {
  1766. err := provider.updateEventAction(action)
  1767. if err == nil {
  1768. if fnReloadRules != nil {
  1769. fnReloadRules()
  1770. }
  1771. executeAction(operationUpdate, executor, ipAddress, actionObjectEventAction, action.Name, role, action)
  1772. }
  1773. return err
  1774. }
  1775. // DeleteEventAction deletes an existing event action
  1776. func DeleteEventAction(name string, executor, ipAddress, role string) error {
  1777. name = config.convertName(name)
  1778. action, err := provider.eventActionExists(name)
  1779. if err != nil {
  1780. return err
  1781. }
  1782. if len(action.Rules) > 0 {
  1783. errorString := fmt.Sprintf("the event action %#q is referenced, it cannot be removed", action.Name)
  1784. return util.NewValidationError(errorString)
  1785. }
  1786. err = provider.deleteEventAction(action)
  1787. if err == nil {
  1788. executeAction(operationDelete, executor, ipAddress, actionObjectEventAction, action.Name, role, &action)
  1789. }
  1790. return err
  1791. }
  1792. // GetEventRules returns an array of event rules respecting limit and offset
  1793. func GetEventRules(limit, offset int, order string) ([]EventRule, error) {
  1794. return provider.getEventRules(limit, offset, order)
  1795. }
  1796. // GetRecentlyUpdatedRules returns the event rules updated after the specified time
  1797. func GetRecentlyUpdatedRules(after int64) ([]EventRule, error) {
  1798. return provider.getRecentlyUpdatedRules(after)
  1799. }
  1800. // EventRuleExists returns the event rule with the given name if it exists
  1801. func EventRuleExists(name string) (EventRule, error) {
  1802. name = config.convertName(name)
  1803. return provider.eventRuleExists(name)
  1804. }
  1805. // AddEventRule adds a new event rule
  1806. func AddEventRule(rule *EventRule, executor, ipAddress, role string) error {
  1807. rule.Name = config.convertName(rule.Name)
  1808. err := provider.addEventRule(rule)
  1809. if err == nil {
  1810. if fnReloadRules != nil {
  1811. fnReloadRules()
  1812. }
  1813. executeAction(operationAdd, executor, ipAddress, actionObjectEventRule, rule.Name, role, rule)
  1814. }
  1815. return err
  1816. }
  1817. // UpdateEventRule updates an existing event rule
  1818. func UpdateEventRule(rule *EventRule, executor, ipAddress, role string) error {
  1819. err := provider.updateEventRule(rule)
  1820. if err == nil {
  1821. if fnReloadRules != nil {
  1822. fnReloadRules()
  1823. }
  1824. executeAction(operationUpdate, executor, ipAddress, actionObjectEventRule, rule.Name, role, rule)
  1825. }
  1826. return err
  1827. }
  1828. // DeleteEventRule deletes an existing event rule
  1829. func DeleteEventRule(name string, executor, ipAddress, role string) error {
  1830. name = config.convertName(name)
  1831. rule, err := provider.eventRuleExists(name)
  1832. if err != nil {
  1833. return err
  1834. }
  1835. err = provider.deleteEventRule(rule, config.IsShared == 1)
  1836. if err == nil {
  1837. if fnRemoveRule != nil {
  1838. fnRemoveRule(rule.Name)
  1839. }
  1840. executeAction(operationDelete, executor, ipAddress, actionObjectEventRule, rule.Name, role, &rule)
  1841. }
  1842. return err
  1843. }
  1844. // RemoveEventRule delets an existing event rule without marking it as deleted
  1845. func RemoveEventRule(rule EventRule) error {
  1846. return provider.deleteEventRule(rule, false)
  1847. }
  1848. // GetTaskByName returns the task with the specified name
  1849. func GetTaskByName(name string) (Task, error) {
  1850. return provider.getTaskByName(name)
  1851. }
  1852. // AddTask add a task with the specified name
  1853. func AddTask(name string) error {
  1854. return provider.addTask(name)
  1855. }
  1856. // UpdateTask updates the task with the specified name and version
  1857. func UpdateTask(name string, version int64) error {
  1858. return provider.updateTask(name, version)
  1859. }
  1860. // UpdateTaskTimestamp updates the timestamp for the task with the specified name
  1861. func UpdateTaskTimestamp(name string) error {
  1862. return provider.updateTaskTimestamp(name)
  1863. }
  1864. // GetNodes returns the other cluster nodes
  1865. func GetNodes() ([]Node, error) {
  1866. if currentNode == nil {
  1867. return nil, nil
  1868. }
  1869. nodes, err := provider.getNodes()
  1870. if err != nil {
  1871. providerLog(logger.LevelError, "unable to get other cluster nodes %v", err)
  1872. }
  1873. return nodes, err
  1874. }
  1875. // GetNodeByName returns a node, different from the current one, by name
  1876. func GetNodeByName(name string) (Node, error) {
  1877. if currentNode == nil {
  1878. return Node{}, util.NewRecordNotFoundError(errNoClusterNodes.Error())
  1879. }
  1880. if name == currentNode.Name {
  1881. return Node{}, util.NewValidationError(fmt.Sprintf("%s is the current node, it must refer to other nodes", name))
  1882. }
  1883. return provider.getNodeByName(name)
  1884. }
  1885. // HasAdmin returns true if the first admin has been created
  1886. // and so SFTPGo is ready to be used
  1887. func HasAdmin() bool {
  1888. return isAdminCreated.Load()
  1889. }
  1890. // AddAdmin adds a new SFTPGo admin
  1891. func AddAdmin(admin *Admin, executor, ipAddress, role string) error {
  1892. admin.Filters.RecoveryCodes = nil
  1893. admin.Filters.TOTPConfig = AdminTOTPConfig{
  1894. Enabled: false,
  1895. }
  1896. admin.Username = config.convertName(admin.Username)
  1897. err := provider.addAdmin(admin)
  1898. if err == nil {
  1899. isAdminCreated.Store(true)
  1900. executeAction(operationAdd, executor, ipAddress, actionObjectAdmin, admin.Username, role, admin)
  1901. }
  1902. return err
  1903. }
  1904. // UpdateAdmin updates an existing SFTPGo admin
  1905. func UpdateAdmin(admin *Admin, executor, ipAddress, role string) error {
  1906. err := provider.updateAdmin(admin)
  1907. if err == nil {
  1908. executeAction(operationUpdate, executor, ipAddress, actionObjectAdmin, admin.Username, role, admin)
  1909. }
  1910. return err
  1911. }
  1912. // DeleteAdmin deletes an existing SFTPGo admin
  1913. func DeleteAdmin(username, executor, ipAddress, role string) error {
  1914. username = config.convertName(username)
  1915. admin, err := provider.adminExists(username)
  1916. if err != nil {
  1917. return err
  1918. }
  1919. err = provider.deleteAdmin(admin)
  1920. if err == nil {
  1921. executeAction(operationDelete, executor, ipAddress, actionObjectAdmin, admin.Username, role, &admin)
  1922. cachedAdminPasswords.Remove(username)
  1923. }
  1924. return err
  1925. }
  1926. // AdminExists returns the admin with the given username if it exists
  1927. func AdminExists(username string) (Admin, error) {
  1928. username = config.convertName(username)
  1929. return provider.adminExists(username)
  1930. }
  1931. // UserExists checks if the given SFTPGo username exists, returns an error if no match is found
  1932. func UserExists(username, role string) (User, error) {
  1933. username = config.convertName(username)
  1934. return provider.userExists(username, role)
  1935. }
  1936. // GetAdminSignature returns the signature for the admin with the specified
  1937. // username.
  1938. func GetAdminSignature(username string) (string, error) {
  1939. username = config.convertName(username)
  1940. return provider.getAdminSignature(username)
  1941. }
  1942. // GetUserSignature returns the signature for the user with the specified
  1943. // username.
  1944. func GetUserSignature(username string) (string, error) {
  1945. username = config.convertName(username)
  1946. return provider.getUserSignature(username)
  1947. }
  1948. // GetUserWithGroupSettings tries to return the user with the specified username
  1949. // loading also the group settings
  1950. func GetUserWithGroupSettings(username, role string) (User, error) {
  1951. username = config.convertName(username)
  1952. user, err := provider.userExists(username, role)
  1953. if err != nil {
  1954. return user, err
  1955. }
  1956. err = user.LoadAndApplyGroupSettings()
  1957. return user, err
  1958. }
  1959. // GetUserVariants tries to return the user with the specified username with and without
  1960. // group settings applied
  1961. func GetUserVariants(username, role string) (User, User, error) {
  1962. username = config.convertName(username)
  1963. user, err := provider.userExists(username, role)
  1964. if err != nil {
  1965. return user, User{}, err
  1966. }
  1967. userWithGroupSettings := user.getACopy()
  1968. err = userWithGroupSettings.LoadAndApplyGroupSettings()
  1969. return user, userWithGroupSettings, err
  1970. }
  1971. // AddUser adds a new SFTPGo user.
  1972. func AddUser(user *User, executor, ipAddress, role string) error {
  1973. user.Username = config.convertName(user.Username)
  1974. err := provider.addUser(user)
  1975. if err == nil {
  1976. executeAction(operationAdd, executor, ipAddress, actionObjectUser, user.Username, role, user)
  1977. }
  1978. return err
  1979. }
  1980. // UpdateUserPassword updates the user password
  1981. func UpdateUserPassword(username, plainPwd, executor, ipAddress, role string) error {
  1982. user, err := provider.userExists(username, role)
  1983. if err != nil {
  1984. return err
  1985. }
  1986. userCopy := user.getACopy()
  1987. if err := userCopy.LoadAndApplyGroupSettings(); err != nil {
  1988. return err
  1989. }
  1990. userCopy.Password = plainPwd
  1991. if err := createUserPasswordHash(&userCopy); err != nil {
  1992. return err
  1993. }
  1994. user.LastPasswordChange = userCopy.LastPasswordChange
  1995. user.Password = userCopy.Password
  1996. user.Filters.RequirePasswordChange = false
  1997. // the last password change is set when validating the user
  1998. if err := provider.updateUser(&user); err != nil {
  1999. return err
  2000. }
  2001. webDAVUsersCache.swap(&user, plainPwd)
  2002. executeAction(operationUpdate, executor, ipAddress, actionObjectUser, username, role, &user)
  2003. return nil
  2004. }
  2005. // UpdateUser updates an existing SFTPGo user.
  2006. func UpdateUser(user *User, executor, ipAddress, role string) error {
  2007. if user.groupSettingsApplied {
  2008. return errors.New("cannot save a user with group settings applied")
  2009. }
  2010. err := provider.updateUser(user)
  2011. if err == nil {
  2012. webDAVUsersCache.swap(user, "")
  2013. executeAction(operationUpdate, executor, ipAddress, actionObjectUser, user.Username, role, user)
  2014. }
  2015. return err
  2016. }
  2017. // DeleteUser deletes an existing SFTPGo user.
  2018. func DeleteUser(username, executor, ipAddress, role string) error {
  2019. username = config.convertName(username)
  2020. user, err := provider.userExists(username, role)
  2021. if err != nil {
  2022. return err
  2023. }
  2024. err = provider.deleteUser(user, config.IsShared == 1)
  2025. if err == nil {
  2026. RemoveCachedWebDAVUser(user.Username)
  2027. delayedQuotaUpdater.resetUserQuota(user.Username)
  2028. cachedUserPasswords.Remove(username)
  2029. executeAction(operationDelete, executor, ipAddress, actionObjectUser, user.Username, role, &user)
  2030. }
  2031. return err
  2032. }
  2033. // AddActiveTransfer stores the specified transfer
  2034. func AddActiveTransfer(transfer ActiveTransfer) {
  2035. if err := provider.addActiveTransfer(transfer); err != nil {
  2036. providerLog(logger.LevelError, "unable to add transfer id %v, connection id %v: %v",
  2037. transfer.ID, transfer.ConnID, err)
  2038. }
  2039. }
  2040. // UpdateActiveTransferSizes updates the current upload and download sizes for the specified transfer
  2041. func UpdateActiveTransferSizes(ulSize, dlSize, transferID int64, connectionID string) {
  2042. if err := provider.updateActiveTransferSizes(ulSize, dlSize, transferID, connectionID); err != nil {
  2043. providerLog(logger.LevelError, "unable to update sizes for transfer id %v, connection id %v: %v",
  2044. transferID, connectionID, err)
  2045. }
  2046. }
  2047. // RemoveActiveTransfer removes the specified transfer
  2048. func RemoveActiveTransfer(transferID int64, connectionID string) {
  2049. if err := provider.removeActiveTransfer(transferID, connectionID); err != nil {
  2050. providerLog(logger.LevelError, "unable to delete transfer id %v, connection id %v: %v",
  2051. transferID, connectionID, err)
  2052. }
  2053. }
  2054. // CleanupActiveTransfers removes the transfer before the specified time
  2055. func CleanupActiveTransfers(before time.Time) error {
  2056. err := provider.cleanupActiveTransfers(before)
  2057. if err == nil {
  2058. providerLog(logger.LevelDebug, "deleted active transfers updated before: %v", before)
  2059. } else {
  2060. providerLog(logger.LevelError, "error deleting active transfers updated before %v: %v", before, err)
  2061. }
  2062. return err
  2063. }
  2064. // GetActiveTransfers retrieves the active transfers with an update time after the specified value
  2065. func GetActiveTransfers(from time.Time) ([]ActiveTransfer, error) {
  2066. return provider.getActiveTransfers(from)
  2067. }
  2068. // AddSharedSession stores a new session within the data provider
  2069. func AddSharedSession(session Session) error {
  2070. err := provider.addSharedSession(session)
  2071. if err != nil {
  2072. providerLog(logger.LevelError, "unable to add shared session, key %q, type: %v, err: %v",
  2073. session.Key, session.Type, err)
  2074. }
  2075. return err
  2076. }
  2077. // DeleteSharedSession deletes the session with the specified key
  2078. func DeleteSharedSession(key string, sessionType SessionType) error {
  2079. err := provider.deleteSharedSession(key, sessionType)
  2080. if err != nil {
  2081. providerLog(logger.LevelError, "unable to add shared session, key %q, err: %v", key, err)
  2082. }
  2083. return err
  2084. }
  2085. // GetSharedSession retrieves the session with the specified key
  2086. func GetSharedSession(key string, sessionType SessionType) (Session, error) {
  2087. return provider.getSharedSession(key, sessionType)
  2088. }
  2089. // CleanupSharedSessions removes the shared session with the specified type and
  2090. // before the specified time
  2091. func CleanupSharedSessions(sessionType SessionType, before time.Time) error {
  2092. err := provider.cleanupSharedSessions(sessionType, util.GetTimeAsMsSinceEpoch(before))
  2093. if err == nil {
  2094. providerLog(logger.LevelDebug, "deleted shared sessions before: %v, type: %v", before, sessionType)
  2095. } else {
  2096. providerLog(logger.LevelError, "error deleting shared session before %v, type %v: %v", before, sessionType, err)
  2097. }
  2098. return err
  2099. }
  2100. // ReloadConfig reloads provider configuration.
  2101. // Currently only implemented for memory provider, allows to reload the users
  2102. // from the configured file, if defined
  2103. func ReloadConfig() error {
  2104. return provider.reloadConfig()
  2105. }
  2106. // GetShares returns an array of shares respecting limit and offset
  2107. func GetShares(limit, offset int, order, username string) ([]Share, error) {
  2108. return provider.getShares(limit, offset, order, username)
  2109. }
  2110. // GetAPIKeys returns an array of API keys respecting limit and offset
  2111. func GetAPIKeys(limit, offset int, order string) ([]APIKey, error) {
  2112. return provider.getAPIKeys(limit, offset, order)
  2113. }
  2114. // GetAdmins returns an array of admins respecting limit and offset
  2115. func GetAdmins(limit, offset int, order string) ([]Admin, error) {
  2116. return provider.getAdmins(limit, offset, order)
  2117. }
  2118. // GetRoles returns an array of roles respecting limit and offset
  2119. func GetRoles(limit, offset int, order string, minimal bool) ([]Role, error) {
  2120. return provider.getRoles(limit, offset, order, minimal)
  2121. }
  2122. // GetGroups returns an array of groups respecting limit and offset
  2123. func GetGroups(limit, offset int, order string, minimal bool) ([]Group, error) {
  2124. return provider.getGroups(limit, offset, order, minimal)
  2125. }
  2126. // GetUsers returns an array of users respecting limit and offset
  2127. func GetUsers(limit, offset int, order, role string) ([]User, error) {
  2128. return provider.getUsers(limit, offset, order, role)
  2129. }
  2130. // GetUsersForQuotaCheck returns the users with the fields required for a quota check
  2131. func GetUsersForQuotaCheck(toFetch map[string]bool) ([]User, error) {
  2132. return provider.getUsersForQuotaCheck(toFetch)
  2133. }
  2134. // AddFolder adds a new virtual folder.
  2135. func AddFolder(folder *vfs.BaseVirtualFolder, executor, ipAddress, role string) error {
  2136. folder.Name = config.convertName(folder.Name)
  2137. err := provider.addFolder(folder)
  2138. if err == nil {
  2139. executeAction(operationAdd, executor, ipAddress, actionObjectFolder, folder.Name, role, &wrappedFolder{Folder: *folder})
  2140. }
  2141. return err
  2142. }
  2143. // UpdateFolder updates the specified virtual folder
  2144. func UpdateFolder(folder *vfs.BaseVirtualFolder, users []string, groups []string, executor, ipAddress, role string) error {
  2145. err := provider.updateFolder(folder)
  2146. if err == nil {
  2147. executeAction(operationUpdate, executor, ipAddress, actionObjectFolder, folder.Name, role, &wrappedFolder{Folder: *folder})
  2148. usersInGroups, errGrp := provider.getUsersInGroups(groups)
  2149. if errGrp == nil {
  2150. users = append(users, usersInGroups...)
  2151. users = util.RemoveDuplicates(users, false)
  2152. } else {
  2153. providerLog(logger.LevelWarn, "unable to get users in groups %+v: %v", groups, errGrp)
  2154. }
  2155. for _, user := range users {
  2156. provider.setUpdatedAt(user)
  2157. u, err := provider.userExists(user, "")
  2158. if err == nil {
  2159. webDAVUsersCache.swap(&u, "")
  2160. executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, u.Role, &u)
  2161. } else {
  2162. RemoveCachedWebDAVUser(user)
  2163. }
  2164. }
  2165. }
  2166. return err
  2167. }
  2168. // DeleteFolder deletes an existing folder.
  2169. func DeleteFolder(folderName, executor, ipAddress, role string) error {
  2170. folderName = config.convertName(folderName)
  2171. folder, err := provider.getFolderByName(folderName)
  2172. if err != nil {
  2173. return err
  2174. }
  2175. err = provider.deleteFolder(folder)
  2176. if err == nil {
  2177. executeAction(operationDelete, executor, ipAddress, actionObjectFolder, folder.Name, role, &wrappedFolder{Folder: folder})
  2178. users := folder.Users
  2179. usersInGroups, errGrp := provider.getUsersInGroups(folder.Groups)
  2180. if errGrp == nil {
  2181. users = append(users, usersInGroups...)
  2182. users = util.RemoveDuplicates(users, false)
  2183. } else {
  2184. providerLog(logger.LevelWarn, "unable to get users in groups %+v: %v", folder.Groups, errGrp)
  2185. }
  2186. for _, user := range users {
  2187. provider.setUpdatedAt(user)
  2188. u, err := provider.userExists(user, "")
  2189. if err == nil {
  2190. executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, u.Role, &u)
  2191. }
  2192. RemoveCachedWebDAVUser(user)
  2193. }
  2194. delayedQuotaUpdater.resetFolderQuota(folderName)
  2195. }
  2196. return err
  2197. }
  2198. // GetFolderByName returns the folder with the specified name if any
  2199. func GetFolderByName(name string) (vfs.BaseVirtualFolder, error) {
  2200. name = config.convertName(name)
  2201. return provider.getFolderByName(name)
  2202. }
  2203. // GetFolders returns an array of folders respecting limit and offset
  2204. func GetFolders(limit, offset int, order string, minimal bool) ([]vfs.BaseVirtualFolder, error) {
  2205. return provider.getFolders(limit, offset, order, minimal)
  2206. }
  2207. func dumpUsers(data *BackupData, scopes []string) error {
  2208. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeUsers) {
  2209. users, err := provider.dumpUsers()
  2210. if err != nil {
  2211. return err
  2212. }
  2213. data.Users = users
  2214. }
  2215. return nil
  2216. }
  2217. func dumpFolders(data *BackupData, scopes []string) error {
  2218. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeFolders) {
  2219. folders, err := provider.dumpFolders()
  2220. if err != nil {
  2221. return err
  2222. }
  2223. data.Folders = folders
  2224. }
  2225. return nil
  2226. }
  2227. func dumpGroups(data *BackupData, scopes []string) error {
  2228. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeGroups) {
  2229. groups, err := provider.dumpGroups()
  2230. if err != nil {
  2231. return err
  2232. }
  2233. data.Groups = groups
  2234. }
  2235. return nil
  2236. }
  2237. func dumpAdmins(data *BackupData, scopes []string) error {
  2238. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeAdmins) {
  2239. admins, err := provider.dumpAdmins()
  2240. if err != nil {
  2241. return err
  2242. }
  2243. data.Admins = admins
  2244. }
  2245. return nil
  2246. }
  2247. func dumpAPIKeys(data *BackupData, scopes []string) error {
  2248. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeAPIKeys) {
  2249. apiKeys, err := provider.dumpAPIKeys()
  2250. if err != nil {
  2251. return err
  2252. }
  2253. data.APIKeys = apiKeys
  2254. }
  2255. return nil
  2256. }
  2257. func dumpShares(data *BackupData, scopes []string) error {
  2258. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeShares) {
  2259. shares, err := provider.dumpShares()
  2260. if err != nil {
  2261. return err
  2262. }
  2263. data.Shares = shares
  2264. }
  2265. return nil
  2266. }
  2267. func dumpActions(data *BackupData, scopes []string) error {
  2268. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeActions) {
  2269. actions, err := provider.dumpEventActions()
  2270. if err != nil {
  2271. return err
  2272. }
  2273. data.EventActions = actions
  2274. }
  2275. return nil
  2276. }
  2277. func dumpRules(data *BackupData, scopes []string) error {
  2278. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeRules) {
  2279. rules, err := provider.dumpEventRules()
  2280. if err != nil {
  2281. return err
  2282. }
  2283. data.EventRules = rules
  2284. }
  2285. return nil
  2286. }
  2287. func dumpRoles(data *BackupData, scopes []string) error {
  2288. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeRoles) {
  2289. roles, err := provider.dumpRoles()
  2290. if err != nil {
  2291. return err
  2292. }
  2293. data.Roles = roles
  2294. }
  2295. return nil
  2296. }
  2297. func dumpIPLists(data *BackupData, scopes []string) error {
  2298. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeIPLists) {
  2299. ipLists, err := provider.dumpIPListEntries()
  2300. if err != nil {
  2301. return err
  2302. }
  2303. data.IPLists = ipLists
  2304. }
  2305. return nil
  2306. }
  2307. func dumpConfigs(data *BackupData, scopes []string) error {
  2308. if len(scopes) == 0 || slices.Contains(scopes, DumpScopeConfigs) {
  2309. configs, err := provider.getConfigs()
  2310. if err != nil {
  2311. return err
  2312. }
  2313. data.Configs = &configs
  2314. }
  2315. return nil
  2316. }
  2317. // DumpData returns a dump containing the requested scopes.
  2318. // Empty scopes means all
  2319. func DumpData(scopes []string) (BackupData, error) {
  2320. data := BackupData{
  2321. Version: DumpVersion,
  2322. }
  2323. if err := dumpGroups(&data, scopes); err != nil {
  2324. return data, err
  2325. }
  2326. if err := dumpUsers(&data, scopes); err != nil {
  2327. return data, err
  2328. }
  2329. if err := dumpFolders(&data, scopes); err != nil {
  2330. return data, err
  2331. }
  2332. if err := dumpAdmins(&data, scopes); err != nil {
  2333. return data, err
  2334. }
  2335. if err := dumpAPIKeys(&data, scopes); err != nil {
  2336. return data, err
  2337. }
  2338. if err := dumpShares(&data, scopes); err != nil {
  2339. return data, err
  2340. }
  2341. if err := dumpActions(&data, scopes); err != nil {
  2342. return data, err
  2343. }
  2344. if err := dumpRules(&data, scopes); err != nil {
  2345. return data, err
  2346. }
  2347. if err := dumpRoles(&data, scopes); err != nil {
  2348. return data, err
  2349. }
  2350. if err := dumpIPLists(&data, scopes); err != nil {
  2351. return data, err
  2352. }
  2353. if err := dumpConfigs(&data, scopes); err != nil {
  2354. return data, err
  2355. }
  2356. return data, nil
  2357. }
  2358. // ParseDumpData tries to parse data as BackupData
  2359. func ParseDumpData(data []byte) (BackupData, error) {
  2360. var dump BackupData
  2361. err := json.Unmarshal(data, &dump)
  2362. return dump, err
  2363. }
  2364. // GetProviderConfig returns the current provider configuration
  2365. func GetProviderConfig() Config {
  2366. return config
  2367. }
  2368. // GetProviderStatus returns an error if the provider is not available
  2369. func GetProviderStatus() ProviderStatus {
  2370. err := provider.checkAvailability()
  2371. status := ProviderStatus{
  2372. Driver: config.Driver,
  2373. }
  2374. if err == nil {
  2375. status.IsActive = true
  2376. } else {
  2377. status.IsActive = false
  2378. status.Error = err.Error()
  2379. }
  2380. return status
  2381. }
  2382. // Close releases all provider resources.
  2383. // This method is used in test cases.
  2384. // Closing an uninitialized provider is not supported
  2385. func Close() error {
  2386. stopScheduler()
  2387. return provider.close()
  2388. }
  2389. func createProvider(basePath string) error {
  2390. sqlPlaceholders = getSQLPlaceholders()
  2391. if err := validateSQLTablesPrefix(); err != nil {
  2392. return err
  2393. }
  2394. logSender = fmt.Sprintf("dataprovider_%v", config.Driver)
  2395. switch config.Driver {
  2396. case SQLiteDataProviderName:
  2397. return initializeSQLiteProvider(basePath)
  2398. case PGSQLDataProviderName, CockroachDataProviderName:
  2399. return initializePGSQLProvider()
  2400. case MySQLDataProviderName:
  2401. return initializeMySQLProvider()
  2402. case BoltDataProviderName:
  2403. return initializeBoltProvider(basePath)
  2404. case MemoryDataProviderName:
  2405. if err := initializeMemoryProvider(basePath); err != nil {
  2406. logger.Warn(logSender, "", "provider initialized but data loading failed: %v", err)
  2407. logger.WarnToConsole("provider initialized but data loading failed: %v", err)
  2408. }
  2409. return nil
  2410. default:
  2411. return fmt.Errorf("unsupported data provider: %v", config.Driver)
  2412. }
  2413. }
  2414. func copyBaseUserFilters(in sdk.BaseUserFilters) sdk.BaseUserFilters {
  2415. filters := sdk.BaseUserFilters{}
  2416. filters.MaxUploadFileSize = in.MaxUploadFileSize
  2417. filters.TLSUsername = in.TLSUsername
  2418. filters.UserType = in.UserType
  2419. filters.AllowedIP = make([]string, len(in.AllowedIP))
  2420. copy(filters.AllowedIP, in.AllowedIP)
  2421. filters.DeniedIP = make([]string, len(in.DeniedIP))
  2422. copy(filters.DeniedIP, in.DeniedIP)
  2423. filters.DeniedLoginMethods = make([]string, len(in.DeniedLoginMethods))
  2424. copy(filters.DeniedLoginMethods, in.DeniedLoginMethods)
  2425. filters.FilePatterns = make([]sdk.PatternsFilter, len(in.FilePatterns))
  2426. copy(filters.FilePatterns, in.FilePatterns)
  2427. filters.DeniedProtocols = make([]string, len(in.DeniedProtocols))
  2428. copy(filters.DeniedProtocols, in.DeniedProtocols)
  2429. filters.TwoFactorAuthProtocols = make([]string, len(in.TwoFactorAuthProtocols))
  2430. copy(filters.TwoFactorAuthProtocols, in.TwoFactorAuthProtocols)
  2431. filters.Hooks.ExternalAuthDisabled = in.Hooks.ExternalAuthDisabled
  2432. filters.Hooks.PreLoginDisabled = in.Hooks.PreLoginDisabled
  2433. filters.Hooks.CheckPasswordDisabled = in.Hooks.CheckPasswordDisabled
  2434. filters.DisableFsChecks = in.DisableFsChecks
  2435. filters.StartDirectory = in.StartDirectory
  2436. filters.FTPSecurity = in.FTPSecurity
  2437. filters.IsAnonymous = in.IsAnonymous
  2438. filters.AllowAPIKeyAuth = in.AllowAPIKeyAuth
  2439. filters.ExternalAuthCacheTime = in.ExternalAuthCacheTime
  2440. filters.DefaultSharesExpiration = in.DefaultSharesExpiration
  2441. filters.MaxSharesExpiration = in.MaxSharesExpiration
  2442. filters.PasswordExpiration = in.PasswordExpiration
  2443. filters.PasswordStrength = in.PasswordStrength
  2444. filters.WebClient = make([]string, len(in.WebClient))
  2445. copy(filters.WebClient, in.WebClient)
  2446. filters.TLSCerts = make([]string, len(in.TLSCerts))
  2447. copy(filters.TLSCerts, in.TLSCerts)
  2448. filters.BandwidthLimits = make([]sdk.BandwidthLimit, 0, len(in.BandwidthLimits))
  2449. for _, limit := range in.BandwidthLimits {
  2450. bwLimit := sdk.BandwidthLimit{
  2451. UploadBandwidth: limit.UploadBandwidth,
  2452. DownloadBandwidth: limit.DownloadBandwidth,
  2453. Sources: make([]string, 0, len(limit.Sources)),
  2454. }
  2455. bwLimit.Sources = make([]string, len(limit.Sources))
  2456. copy(bwLimit.Sources, limit.Sources)
  2457. filters.BandwidthLimits = append(filters.BandwidthLimits, bwLimit)
  2458. }
  2459. filters.AccessTime = make([]sdk.TimePeriod, 0, len(in.AccessTime))
  2460. for _, period := range in.AccessTime {
  2461. filters.AccessTime = append(filters.AccessTime, sdk.TimePeriod{
  2462. DayOfWeek: period.DayOfWeek,
  2463. From: period.From,
  2464. To: period.To,
  2465. })
  2466. }
  2467. return filters
  2468. }
  2469. func buildUserHomeDir(user *User) {
  2470. if user.HomeDir == "" {
  2471. if config.UsersBaseDir != "" {
  2472. user.HomeDir = filepath.Join(config.UsersBaseDir, user.Username)
  2473. return
  2474. }
  2475. switch user.FsConfig.Provider {
  2476. case sdk.SFTPFilesystemProvider, sdk.S3FilesystemProvider, sdk.AzureBlobFilesystemProvider, sdk.GCSFilesystemProvider, sdk.HTTPFilesystemProvider:
  2477. if tempPath != "" {
  2478. user.HomeDir = filepath.Join(tempPath, user.Username)
  2479. } else {
  2480. user.HomeDir = filepath.Join(os.TempDir(), user.Username)
  2481. }
  2482. }
  2483. } else {
  2484. user.HomeDir = filepath.Clean(user.HomeDir)
  2485. }
  2486. }
  2487. func validateFolderQuotaLimits(folder vfs.VirtualFolder) error {
  2488. if folder.QuotaSize < -1 {
  2489. return util.NewI18nError(
  2490. util.NewValidationError(fmt.Sprintf("invalid quota_size: %v folder path %q", folder.QuotaSize, folder.MappedPath)),
  2491. util.I18nErrorFolderQuotaSizeInvalid,
  2492. )
  2493. }
  2494. if folder.QuotaFiles < -1 {
  2495. return util.NewI18nError(
  2496. util.NewValidationError(fmt.Sprintf("invalid quota_file: %v folder path %q", folder.QuotaFiles, folder.MappedPath)),
  2497. util.I18nErrorFolderQuotaFileInvalid,
  2498. )
  2499. }
  2500. if (folder.QuotaSize == -1 && folder.QuotaFiles != -1) || (folder.QuotaFiles == -1 && folder.QuotaSize != -1) {
  2501. return util.NewI18nError(
  2502. util.NewValidationError(fmt.Sprintf("virtual folder quota_size and quota_files must be both -1 or >= 0, quota_size: %v quota_files: %v",
  2503. folder.QuotaFiles, folder.QuotaSize)),
  2504. util.I18nErrorFolderQuotaInvalid,
  2505. )
  2506. }
  2507. return nil
  2508. }
  2509. func validateUserGroups(user *User) error {
  2510. if len(user.Groups) == 0 {
  2511. return nil
  2512. }
  2513. hasPrimary := false
  2514. groupNames := make(map[string]bool)
  2515. for _, g := range user.Groups {
  2516. if g.Type < sdk.GroupTypePrimary && g.Type > sdk.GroupTypeMembership {
  2517. return util.NewValidationError(fmt.Sprintf("invalid group type: %v", g.Type))
  2518. }
  2519. if g.Type == sdk.GroupTypePrimary {
  2520. if hasPrimary {
  2521. return util.NewI18nError(
  2522. util.NewValidationError("only one primary group is allowed"),
  2523. util.I18nErrorPrimaryGroup,
  2524. )
  2525. }
  2526. hasPrimary = true
  2527. }
  2528. if groupNames[g.Name] {
  2529. return util.NewI18nError(
  2530. util.NewValidationError(fmt.Sprintf("the group %q is duplicated", g.Name)),
  2531. util.I18nErrorDuplicateGroup,
  2532. )
  2533. }
  2534. groupNames[g.Name] = true
  2535. }
  2536. return nil
  2537. }
  2538. func validateAssociatedVirtualFolders(vfolders []vfs.VirtualFolder) ([]vfs.VirtualFolder, error) {
  2539. if len(vfolders) == 0 {
  2540. return []vfs.VirtualFolder{}, nil
  2541. }
  2542. var virtualFolders []vfs.VirtualFolder
  2543. folderNames := make(map[string]bool)
  2544. for _, v := range vfolders {
  2545. if v.VirtualPath == "" {
  2546. return nil, util.NewI18nError(
  2547. util.NewValidationError("mount/virtual path is mandatory"),
  2548. util.I18nErrorFolderMountPathRequired,
  2549. )
  2550. }
  2551. cleanedVPath := util.CleanPath(v.VirtualPath)
  2552. if err := validateFolderQuotaLimits(v); err != nil {
  2553. return nil, err
  2554. }
  2555. if v.Name == "" {
  2556. return nil, util.NewI18nError(util.NewValidationError("folder name is mandatory"), util.I18nErrorFolderNameRequired)
  2557. }
  2558. if folderNames[v.Name] {
  2559. return nil, util.NewI18nError(
  2560. util.NewValidationError(fmt.Sprintf("the folder %q is duplicated", v.Name)),
  2561. util.I18nErrorDuplicatedFolders,
  2562. )
  2563. }
  2564. for _, vFolder := range virtualFolders {
  2565. if util.IsDirOverlapped(vFolder.VirtualPath, cleanedVPath, false, "/") {
  2566. return nil, util.NewI18nError(
  2567. util.NewValidationError(fmt.Sprintf("invalid virtual folder %q, it overlaps with virtual folder %q",
  2568. v.VirtualPath, vFolder.VirtualPath)),
  2569. util.I18nErrorOverlappedFolders,
  2570. )
  2571. }
  2572. }
  2573. virtualFolders = append(virtualFolders, vfs.VirtualFolder{
  2574. BaseVirtualFolder: vfs.BaseVirtualFolder{
  2575. Name: v.Name,
  2576. },
  2577. VirtualPath: cleanedVPath,
  2578. QuotaSize: v.QuotaSize,
  2579. QuotaFiles: v.QuotaFiles,
  2580. })
  2581. folderNames[v.Name] = true
  2582. }
  2583. return virtualFolders, nil
  2584. }
  2585. func validateUserTOTPConfig(c *UserTOTPConfig, username string) error {
  2586. if !c.Enabled {
  2587. c.ConfigName = ""
  2588. c.Secret = kms.NewEmptySecret()
  2589. c.Protocols = nil
  2590. return nil
  2591. }
  2592. if c.ConfigName == "" {
  2593. return util.NewValidationError("totp: config name is mandatory")
  2594. }
  2595. if !slices.Contains(mfa.GetAvailableTOTPConfigNames(), c.ConfigName) {
  2596. return util.NewValidationError(fmt.Sprintf("totp: config name %q not found", c.ConfigName))
  2597. }
  2598. if c.Secret.IsEmpty() {
  2599. return util.NewValidationError("totp: secret is mandatory")
  2600. }
  2601. if c.Secret.IsPlain() {
  2602. c.Secret.SetAdditionalData(username)
  2603. if err := c.Secret.Encrypt(); err != nil {
  2604. return util.NewValidationError(fmt.Sprintf("totp: unable to encrypt secret: %v", err))
  2605. }
  2606. }
  2607. if len(c.Protocols) == 0 {
  2608. return util.NewValidationError("totp: specify at least one protocol")
  2609. }
  2610. for _, protocol := range c.Protocols {
  2611. if !slices.Contains(MFAProtocols, protocol) {
  2612. return util.NewValidationError(fmt.Sprintf("totp: invalid protocol %q", protocol))
  2613. }
  2614. }
  2615. return nil
  2616. }
  2617. func validateUserRecoveryCodes(user *User) error {
  2618. for i := 0; i < len(user.Filters.RecoveryCodes); i++ {
  2619. code := &user.Filters.RecoveryCodes[i]
  2620. if code.Secret.IsEmpty() {
  2621. return util.NewValidationError("mfa: recovery code cannot be empty")
  2622. }
  2623. if code.Secret.IsPlain() {
  2624. code.Secret.SetAdditionalData(user.Username)
  2625. if err := code.Secret.Encrypt(); err != nil {
  2626. return util.NewValidationError(fmt.Sprintf("mfa: unable to encrypt recovery code: %v", err))
  2627. }
  2628. }
  2629. }
  2630. return nil
  2631. }
  2632. func validateUserPermissions(permsToCheck map[string][]string) (map[string][]string, error) {
  2633. permissions := make(map[string][]string)
  2634. for dir, perms := range permsToCheck {
  2635. if len(perms) == 0 && dir == "/" {
  2636. return permissions, util.NewValidationError(fmt.Sprintf("no permissions granted for the directory: %q", dir))
  2637. }
  2638. if len(perms) > len(ValidPerms) {
  2639. return permissions, util.NewValidationError("invalid permissions")
  2640. }
  2641. for _, p := range perms {
  2642. if !slices.Contains(ValidPerms, p) {
  2643. return permissions, util.NewValidationError(fmt.Sprintf("invalid permission: %q", p))
  2644. }
  2645. }
  2646. cleanedDir := filepath.ToSlash(path.Clean(dir))
  2647. if cleanedDir != "/" {
  2648. cleanedDir = strings.TrimSuffix(cleanedDir, "/")
  2649. }
  2650. if !path.IsAbs(cleanedDir) {
  2651. return permissions, util.NewValidationError(fmt.Sprintf("cannot set permissions for non absolute path: %q", dir))
  2652. }
  2653. if dir != cleanedDir && cleanedDir == "/" {
  2654. return permissions, util.NewValidationError(fmt.Sprintf("cannot set permissions for invalid subdirectory: %q is an alias for \"/\"", dir))
  2655. }
  2656. if slices.Contains(perms, PermAny) {
  2657. permissions[cleanedDir] = []string{PermAny}
  2658. } else {
  2659. permissions[cleanedDir] = util.RemoveDuplicates(perms, false)
  2660. }
  2661. }
  2662. return permissions, nil
  2663. }
  2664. func validatePermissions(user *User) error {
  2665. if len(user.Permissions) == 0 {
  2666. return util.NewI18nError(util.NewValidationError("please grant some permissions to this user"), util.I18nErrorNoPermission)
  2667. }
  2668. if _, ok := user.Permissions["/"]; !ok {
  2669. return util.NewI18nError(util.NewValidationError("permissions for the root dir \"/\" must be set"), util.I18nErrorNoRootPermission)
  2670. }
  2671. permissions, err := validateUserPermissions(user.Permissions)
  2672. if err != nil {
  2673. return util.NewI18nError(err, util.I18nErrorGenericPermission)
  2674. }
  2675. user.Permissions = permissions
  2676. return nil
  2677. }
  2678. func validatePublicKeys(user *User) error {
  2679. if len(user.PublicKeys) == 0 {
  2680. user.PublicKeys = []string{}
  2681. }
  2682. var validatedKeys []string
  2683. for idx, key := range user.PublicKeys {
  2684. if key == "" {
  2685. continue
  2686. }
  2687. out, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key))
  2688. if err != nil {
  2689. return util.NewI18nError(
  2690. util.NewValidationError(fmt.Sprintf("error parsing public key at position %d: %v", idx, err)),
  2691. util.I18nErrorPubKeyInvalid,
  2692. )
  2693. }
  2694. if out.Type() == ssh.InsecureKeyAlgoDSA {
  2695. providerLog(logger.LevelError, "dsa public key not accepted, position: %d", idx)
  2696. return util.NewI18nError(
  2697. util.NewValidationError(fmt.Sprintf("DSA key format is insecure and it is not allowed for key at position %d", idx)),
  2698. util.I18nErrorKeyInsecure,
  2699. )
  2700. }
  2701. if k, ok := out.(ssh.CryptoPublicKey); ok {
  2702. cryptoKey := k.CryptoPublicKey()
  2703. if rsaKey, ok := cryptoKey.(*rsa.PublicKey); ok {
  2704. if size := rsaKey.N.BitLen(); size < 2048 {
  2705. providerLog(logger.LevelError, "rsa key with size %d at position %d not accepted, minimum 2048", size, idx)
  2706. return util.NewI18nError(
  2707. util.NewValidationError(fmt.Sprintf("invalid size %d for rsa key at position %d, minimum 2048",
  2708. size, idx)),
  2709. util.I18nErrorKeySizeInvalid,
  2710. )
  2711. }
  2712. }
  2713. }
  2714. validatedKeys = append(validatedKeys, key)
  2715. }
  2716. user.PublicKeys = util.RemoveDuplicates(validatedKeys, false)
  2717. return nil
  2718. }
  2719. func validateFiltersPatternExtensions(baseFilters *sdk.BaseUserFilters) error {
  2720. if len(baseFilters.FilePatterns) == 0 {
  2721. baseFilters.FilePatterns = []sdk.PatternsFilter{}
  2722. return nil
  2723. }
  2724. filteredPaths := []string{}
  2725. var filters []sdk.PatternsFilter
  2726. for _, f := range baseFilters.FilePatterns {
  2727. cleanedPath := filepath.ToSlash(path.Clean(f.Path))
  2728. if !path.IsAbs(cleanedPath) {
  2729. return util.NewI18nError(
  2730. util.NewValidationError(fmt.Sprintf("invalid path %q for file patterns filter", f.Path)),
  2731. util.I18nErrorFilePatternPathInvalid,
  2732. )
  2733. }
  2734. if slices.Contains(filteredPaths, cleanedPath) {
  2735. return util.NewI18nError(
  2736. util.NewValidationError(fmt.Sprintf("duplicate file patterns filter for path %q", f.Path)),
  2737. util.I18nErrorFilePatternDuplicated,
  2738. )
  2739. }
  2740. if len(f.AllowedPatterns) == 0 && len(f.DeniedPatterns) == 0 {
  2741. return util.NewValidationError(fmt.Sprintf("empty file patterns filter for path %q", f.Path))
  2742. }
  2743. if f.DenyPolicy < sdk.DenyPolicyDefault || f.DenyPolicy > sdk.DenyPolicyHide {
  2744. return util.NewValidationError(fmt.Sprintf("invalid deny policy %v for path %q", f.DenyPolicy, f.Path))
  2745. }
  2746. f.Path = cleanedPath
  2747. allowed := make([]string, 0, len(f.AllowedPatterns))
  2748. denied := make([]string, 0, len(f.DeniedPatterns))
  2749. for _, pattern := range f.AllowedPatterns {
  2750. _, err := path.Match(pattern, "abc")
  2751. if err != nil {
  2752. return util.NewI18nError(
  2753. util.NewValidationError(fmt.Sprintf("invalid file pattern filter %q", pattern)),
  2754. util.I18nErrorFilePatternInvalid,
  2755. )
  2756. }
  2757. allowed = append(allowed, strings.ToLower(pattern))
  2758. }
  2759. for _, pattern := range f.DeniedPatterns {
  2760. _, err := path.Match(pattern, "abc")
  2761. if err != nil {
  2762. return util.NewI18nError(
  2763. util.NewValidationError(fmt.Sprintf("invalid file pattern filter %q", pattern)),
  2764. util.I18nErrorFilePatternInvalid,
  2765. )
  2766. }
  2767. denied = append(denied, strings.ToLower(pattern))
  2768. }
  2769. f.AllowedPatterns = util.RemoveDuplicates(allowed, false)
  2770. f.DeniedPatterns = util.RemoveDuplicates(denied, false)
  2771. filters = append(filters, f)
  2772. filteredPaths = append(filteredPaths, cleanedPath)
  2773. }
  2774. baseFilters.FilePatterns = filters
  2775. return nil
  2776. }
  2777. func checkEmptyFiltersStruct(filters *sdk.BaseUserFilters) {
  2778. if len(filters.AllowedIP) == 0 {
  2779. filters.AllowedIP = []string{}
  2780. }
  2781. if len(filters.DeniedIP) == 0 {
  2782. filters.DeniedIP = []string{}
  2783. }
  2784. if len(filters.DeniedLoginMethods) == 0 {
  2785. filters.DeniedLoginMethods = []string{}
  2786. }
  2787. if len(filters.DeniedProtocols) == 0 {
  2788. filters.DeniedProtocols = []string{}
  2789. }
  2790. }
  2791. func validateIPFilters(filters *sdk.BaseUserFilters) error {
  2792. filters.DeniedIP = util.RemoveDuplicates(filters.DeniedIP, false)
  2793. for _, IPMask := range filters.DeniedIP {
  2794. _, _, err := net.ParseCIDR(IPMask)
  2795. if err != nil {
  2796. return util.NewValidationError(fmt.Sprintf("could not parse denied IP/Mask %q: %v", IPMask, err))
  2797. }
  2798. }
  2799. filters.AllowedIP = util.RemoveDuplicates(filters.AllowedIP, false)
  2800. for _, IPMask := range filters.AllowedIP {
  2801. _, _, err := net.ParseCIDR(IPMask)
  2802. if err != nil {
  2803. return util.NewValidationError(fmt.Sprintf("could not parse allowed IP/Mask %q: %v", IPMask, err))
  2804. }
  2805. }
  2806. return nil
  2807. }
  2808. func validateBandwidthLimit(bl sdk.BandwidthLimit) error {
  2809. if len(bl.Sources) == 0 {
  2810. return util.NewValidationError("no bandwidth limit source specified")
  2811. }
  2812. for _, source := range bl.Sources {
  2813. _, _, err := net.ParseCIDR(source)
  2814. if err != nil {
  2815. return util.NewValidationError(fmt.Sprintf("could not parse bandwidth limit source %q: %v", source, err))
  2816. }
  2817. }
  2818. return nil
  2819. }
  2820. func validateBandwidthLimitsFilter(filters *sdk.BaseUserFilters) error {
  2821. for idx, bandwidthLimit := range filters.BandwidthLimits {
  2822. if err := validateBandwidthLimit(bandwidthLimit); err != nil {
  2823. return err
  2824. }
  2825. if bandwidthLimit.DownloadBandwidth < 0 {
  2826. filters.BandwidthLimits[idx].DownloadBandwidth = 0
  2827. }
  2828. if bandwidthLimit.UploadBandwidth < 0 {
  2829. filters.BandwidthLimits[idx].UploadBandwidth = 0
  2830. }
  2831. }
  2832. return nil
  2833. }
  2834. func updateFiltersValues(filters *sdk.BaseUserFilters) {
  2835. if filters.StartDirectory != "" {
  2836. filters.StartDirectory = util.CleanPath(filters.StartDirectory)
  2837. if filters.StartDirectory == "/" {
  2838. filters.StartDirectory = ""
  2839. }
  2840. }
  2841. }
  2842. func validateFilterProtocols(filters *sdk.BaseUserFilters) error {
  2843. if len(filters.DeniedProtocols) >= len(ValidProtocols) {
  2844. return util.NewValidationError("invalid denied_protocols")
  2845. }
  2846. for _, p := range filters.DeniedProtocols {
  2847. if !slices.Contains(ValidProtocols, p) {
  2848. return util.NewValidationError(fmt.Sprintf("invalid denied protocol %q", p))
  2849. }
  2850. }
  2851. for _, p := range filters.TwoFactorAuthProtocols {
  2852. if !slices.Contains(MFAProtocols, p) {
  2853. return util.NewValidationError(fmt.Sprintf("invalid two factor protocol %q", p))
  2854. }
  2855. }
  2856. return nil
  2857. }
  2858. func validateTLSCerts(certs []string) ([]string, error) {
  2859. var validateCerts []string
  2860. for idx, cert := range certs {
  2861. if cert == "" {
  2862. continue
  2863. }
  2864. derBlock, _ := pem.Decode([]byte(cert))
  2865. if derBlock == nil {
  2866. return nil, util.NewI18nError(
  2867. util.NewValidationError(fmt.Sprintf("invalid TLS certificate %d", idx)),
  2868. util.I18nErrorInvalidTLSCert,
  2869. )
  2870. }
  2871. crt, err := x509.ParseCertificate(derBlock.Bytes)
  2872. if err != nil {
  2873. return nil, util.NewI18nError(
  2874. util.NewValidationError(fmt.Sprintf("error parsing TLS certificate %d", idx)),
  2875. util.I18nErrorInvalidTLSCert,
  2876. )
  2877. }
  2878. if crt.PublicKeyAlgorithm == x509.RSA {
  2879. if rsaCert, ok := crt.PublicKey.(*rsa.PublicKey); ok {
  2880. if size := rsaCert.N.BitLen(); size < 2048 {
  2881. providerLog(logger.LevelError, "rsa cert with size %d not accepted, minimum 2048", size)
  2882. return nil, util.NewI18nError(
  2883. util.NewValidationError(fmt.Sprintf("invalid size %d for rsa cert at position %d, minimum 2048",
  2884. size, idx)),
  2885. util.I18nErrorKeySizeInvalid,
  2886. )
  2887. }
  2888. }
  2889. }
  2890. validateCerts = append(validateCerts, cert)
  2891. }
  2892. return validateCerts, nil
  2893. }
  2894. func validateBaseFilters(filters *sdk.BaseUserFilters) error {
  2895. checkEmptyFiltersStruct(filters)
  2896. if err := validateIPFilters(filters); err != nil {
  2897. return util.NewI18nError(err, util.I18nErrorIPFiltersInvalid)
  2898. }
  2899. if err := validateBandwidthLimitsFilter(filters); err != nil {
  2900. return util.NewI18nError(err, util.I18nErrorSourceBWLimitInvalid)
  2901. }
  2902. if len(filters.DeniedLoginMethods) >= len(ValidLoginMethods) {
  2903. return util.NewValidationError("invalid denied_login_methods")
  2904. }
  2905. for _, loginMethod := range filters.DeniedLoginMethods {
  2906. if !slices.Contains(ValidLoginMethods, loginMethod) {
  2907. return util.NewValidationError(fmt.Sprintf("invalid login method: %q", loginMethod))
  2908. }
  2909. }
  2910. if err := validateFilterProtocols(filters); err != nil {
  2911. return err
  2912. }
  2913. if filters.TLSUsername != "" {
  2914. if !slices.Contains(validTLSUsernames, string(filters.TLSUsername)) {
  2915. return util.NewValidationError(fmt.Sprintf("invalid TLS username: %q", filters.TLSUsername))
  2916. }
  2917. }
  2918. certs, err := validateTLSCerts(filters.TLSCerts)
  2919. if err != nil {
  2920. return err
  2921. }
  2922. filters.TLSCerts = certs
  2923. for _, opts := range filters.WebClient {
  2924. if !slices.Contains(sdk.WebClientOptions, opts) {
  2925. return util.NewValidationError(fmt.Sprintf("invalid web client options %q", opts))
  2926. }
  2927. }
  2928. if filters.MaxSharesExpiration > 0 && filters.MaxSharesExpiration < filters.DefaultSharesExpiration {
  2929. return util.NewI18nError(
  2930. util.NewValidationError(fmt.Sprintf("default shares expiration: %d must be less than or equal to max shares expiration: %d",
  2931. filters.DefaultSharesExpiration, filters.MaxSharesExpiration)),
  2932. util.I18nErrorShareExpirationInvalid,
  2933. )
  2934. }
  2935. updateFiltersValues(filters)
  2936. if err := validateAccessTimeFilters(filters); err != nil {
  2937. return err
  2938. }
  2939. return validateFiltersPatternExtensions(filters)
  2940. }
  2941. func isTimeOfDayValid(value string) bool {
  2942. if len(value) != 5 {
  2943. return false
  2944. }
  2945. parts := strings.Split(value, ":")
  2946. if len(parts) != 2 {
  2947. return false
  2948. }
  2949. hour, err := strconv.Atoi(parts[0])
  2950. if err != nil {
  2951. return false
  2952. }
  2953. if hour < 0 || hour > 23 {
  2954. return false
  2955. }
  2956. minute, err := strconv.Atoi(parts[1])
  2957. if err != nil {
  2958. return false
  2959. }
  2960. if minute < 0 || minute > 59 {
  2961. return false
  2962. }
  2963. return true
  2964. }
  2965. func validateAccessTimeFilters(filters *sdk.BaseUserFilters) error {
  2966. for _, period := range filters.AccessTime {
  2967. if period.DayOfWeek < int(time.Sunday) || period.DayOfWeek > int(time.Saturday) {
  2968. return util.NewValidationError(fmt.Sprintf("invalid day of week: %d", period.DayOfWeek))
  2969. }
  2970. if !isTimeOfDayValid(period.From) || !isTimeOfDayValid(period.To) {
  2971. return util.NewI18nError(
  2972. util.NewValidationError("invalid time of day. Supported format: HH:MM"),
  2973. util.I18nErrorTimeOfDayInvalid,
  2974. )
  2975. }
  2976. if period.To <= period.From {
  2977. return util.NewI18nError(
  2978. util.NewValidationError("invalid time of day. The end time cannot be earlier than the start time"),
  2979. util.I18nErrorTimeOfDayConflict,
  2980. )
  2981. }
  2982. }
  2983. return nil
  2984. }
  2985. func validateCombinedUserFilters(user *User) error {
  2986. if user.Filters.TOTPConfig.Enabled && slices.Contains(user.Filters.WebClient, sdk.WebClientMFADisabled) {
  2987. return util.NewI18nError(
  2988. util.NewValidationError("two-factor authentication cannot be disabled for a user with an active configuration"),
  2989. util.I18nErrorDisableActive2FA,
  2990. )
  2991. }
  2992. if user.Filters.RequirePasswordChange && slices.Contains(user.Filters.WebClient, sdk.WebClientPasswordChangeDisabled) {
  2993. return util.NewI18nError(
  2994. util.NewValidationError("you cannot require password change and at the same time disallow it"),
  2995. util.I18nErrorPwdChangeConflict,
  2996. )
  2997. }
  2998. if len(user.Filters.TwoFactorAuthProtocols) > 0 && slices.Contains(user.Filters.WebClient, sdk.WebClientMFADisabled) {
  2999. return util.NewI18nError(
  3000. util.NewValidationError("you cannot require two-factor authentication and at the same time disallow it"),
  3001. util.I18nError2FAConflict,
  3002. )
  3003. }
  3004. return nil
  3005. }
  3006. func validateEmails(user *User) error {
  3007. if user.Email != "" && !util.IsEmailValid(user.Email) {
  3008. return util.NewI18nError(
  3009. util.NewValidationError(fmt.Sprintf("email %q is not valid", user.Email)),
  3010. util.I18nErrorInvalidEmail,
  3011. )
  3012. }
  3013. for _, email := range user.Filters.AdditionalEmails {
  3014. if !util.IsEmailValid(email) {
  3015. return util.NewI18nError(
  3016. util.NewValidationError(fmt.Sprintf("email %q is not valid", email)),
  3017. util.I18nErrorInvalidEmail,
  3018. )
  3019. }
  3020. }
  3021. return nil
  3022. }
  3023. func validateBaseParams(user *User) error {
  3024. if user.Username == "" {
  3025. return util.NewI18nError(util.NewValidationError("username is mandatory"), util.I18nErrorUsernameRequired)
  3026. }
  3027. if err := checkReservedUsernames(user.Username); err != nil {
  3028. return util.NewI18nError(err, util.I18nErrorReservedUsername)
  3029. }
  3030. if err := validateEmails(user); err != nil {
  3031. return err
  3032. }
  3033. if config.NamingRules&1 == 0 && !usernameRegex.MatchString(user.Username) {
  3034. return util.NewI18nError(
  3035. util.NewValidationError(fmt.Sprintf("username %q is not valid, the following characters are allowed: a-zA-Z0-9-_.~", user.Username)),
  3036. util.I18nErrorInvalidUser,
  3037. )
  3038. }
  3039. if user.hasRedactedSecret() {
  3040. return util.NewValidationError("cannot save a user with a redacted secret")
  3041. }
  3042. if user.HomeDir == "" {
  3043. return util.NewI18nError(util.NewValidationError("home_dir is mandatory"), util.I18nErrorHomeRequired)
  3044. }
  3045. // we can have users with no passwords and public keys, they can authenticate via SSH user certs or OIDC
  3046. /*if user.Password == "" && len(user.PublicKeys) == 0 {
  3047. return util.NewValidationError("please set a password or at least a public_key")
  3048. }*/
  3049. if !filepath.IsAbs(user.HomeDir) {
  3050. return util.NewI18nError(
  3051. util.NewValidationError(fmt.Sprintf("home_dir must be an absolute path, actual value: %v", user.HomeDir)),
  3052. util.I18nErrorHomeInvalid,
  3053. )
  3054. }
  3055. if user.DownloadBandwidth < 0 {
  3056. user.DownloadBandwidth = 0
  3057. }
  3058. if user.UploadBandwidth < 0 {
  3059. user.UploadBandwidth = 0
  3060. }
  3061. if user.TotalDataTransfer > 0 {
  3062. // if a total data transfer is defined we reset the separate upload and download limits
  3063. user.UploadDataTransfer = 0
  3064. user.DownloadDataTransfer = 0
  3065. }
  3066. if user.Filters.IsAnonymous {
  3067. user.setAnonymousSettings()
  3068. }
  3069. err := user.FsConfig.Validate(user.GetEncryptionAdditionalData())
  3070. if err != nil {
  3071. return err
  3072. }
  3073. return nil
  3074. }
  3075. func hashPlainPassword(plainPwd string) (string, error) {
  3076. if config.PasswordHashing.Algo == HashingAlgoBcrypt {
  3077. pwd, err := bcrypt.GenerateFromPassword([]byte(plainPwd), config.PasswordHashing.BcryptOptions.Cost)
  3078. if err != nil {
  3079. return "", fmt.Errorf("bcrypt hashing error: %w", err)
  3080. }
  3081. return util.BytesToString(pwd), nil
  3082. }
  3083. pwd, err := argon2id.CreateHash(plainPwd, argon2Params)
  3084. if err != nil {
  3085. return "", fmt.Errorf("argon2ID hashing error: %w", err)
  3086. }
  3087. return pwd, nil
  3088. }
  3089. func createUserPasswordHash(user *User) error {
  3090. if user.Password != "" && !user.IsPasswordHashed() {
  3091. if minEntropy := user.getMinPasswordEntropy(); minEntropy > 0 {
  3092. if err := passwordvalidator.Validate(user.Password, minEntropy); err != nil {
  3093. return util.NewI18nError(util.NewValidationError(err.Error()), util.I18nErrorPasswordComplexity)
  3094. }
  3095. }
  3096. hashedPwd, err := hashPlainPassword(user.Password)
  3097. if err != nil {
  3098. return err
  3099. }
  3100. user.Password = hashedPwd
  3101. user.LastPasswordChange = util.GetTimeAsMsSinceEpoch(time.Now())
  3102. }
  3103. return nil
  3104. }
  3105. // ValidateFolder returns an error if the folder is not valid
  3106. // FIXME: this should be defined as Folder struct method
  3107. func ValidateFolder(folder *vfs.BaseVirtualFolder) error {
  3108. folder.FsConfig.SetEmptySecretsIfNil()
  3109. if folder.Name == "" {
  3110. return util.NewI18nError(util.NewValidationError("folder name is mandatory"), util.I18nErrorNameRequired)
  3111. }
  3112. if config.NamingRules&1 == 0 && !usernameRegex.MatchString(folder.Name) {
  3113. return util.NewI18nError(
  3114. util.NewValidationError(fmt.Sprintf("folder name %q is not valid, the following characters are allowed: a-zA-Z0-9-_.~", folder.Name)),
  3115. util.I18nErrorInvalidName,
  3116. )
  3117. }
  3118. if folder.FsConfig.Provider == sdk.LocalFilesystemProvider || folder.FsConfig.Provider == sdk.CryptedFilesystemProvider ||
  3119. folder.MappedPath != "" {
  3120. cleanedMPath := filepath.Clean(folder.MappedPath)
  3121. if !filepath.IsAbs(cleanedMPath) {
  3122. return util.NewI18nError(
  3123. util.NewValidationError(fmt.Sprintf("invalid folder mapped path %q", folder.MappedPath)),
  3124. util.I18nErrorInvalidHomeDir,
  3125. )
  3126. }
  3127. folder.MappedPath = cleanedMPath
  3128. }
  3129. if folder.HasRedactedSecret() {
  3130. return errors.New("cannot save a folder with a redacted secret")
  3131. }
  3132. return folder.FsConfig.Validate(folder.GetEncryptionAdditionalData())
  3133. }
  3134. // ValidateUser returns an error if the user is not valid
  3135. // FIXME: this should be defined as User struct method
  3136. func ValidateUser(user *User) error {
  3137. user.OIDCCustomFields = nil
  3138. user.HasPassword = false
  3139. user.SetEmptySecretsIfNil()
  3140. buildUserHomeDir(user)
  3141. if err := validateBaseParams(user); err != nil {
  3142. return err
  3143. }
  3144. if err := validateUserGroups(user); err != nil {
  3145. return err
  3146. }
  3147. if err := validatePermissions(user); err != nil {
  3148. return err
  3149. }
  3150. if err := validateUserTOTPConfig(&user.Filters.TOTPConfig, user.Username); err != nil {
  3151. return util.NewI18nError(err, util.I18nError2FAInvalid)
  3152. }
  3153. if err := validateUserRecoveryCodes(user); err != nil {
  3154. return util.NewI18nError(err, util.I18nErrorRecoveryCodesInvalid)
  3155. }
  3156. vfolders, err := validateAssociatedVirtualFolders(user.VirtualFolders)
  3157. if err != nil {
  3158. return err
  3159. }
  3160. user.VirtualFolders = vfolders
  3161. if user.Status < 0 || user.Status > 1 {
  3162. return util.NewValidationError(fmt.Sprintf("invalid user status: %v", user.Status))
  3163. }
  3164. if err := createUserPasswordHash(user); err != nil {
  3165. return err
  3166. }
  3167. if err := validatePublicKeys(user); err != nil {
  3168. return err
  3169. }
  3170. if err := validateBaseFilters(&user.Filters.BaseUserFilters); err != nil {
  3171. return err
  3172. }
  3173. if !user.HasExternalAuth() {
  3174. user.Filters.ExternalAuthCacheTime = 0
  3175. }
  3176. return validateCombinedUserFilters(user)
  3177. }
  3178. func isPasswordOK(user *User, password string) (bool, error) {
  3179. if config.PasswordCaching {
  3180. found, match := cachedUserPasswords.Check(user.Username, password, user.Password)
  3181. if found {
  3182. return match, nil
  3183. }
  3184. }
  3185. match := false
  3186. updatePwd := true
  3187. var err error
  3188. switch {
  3189. case strings.HasPrefix(user.Password, bcryptPwdPrefix):
  3190. if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
  3191. return match, ErrInvalidCredentials
  3192. }
  3193. match = true
  3194. updatePwd = config.PasswordHashing.Algo != HashingAlgoBcrypt
  3195. case strings.HasPrefix(user.Password, argonPwdPrefix):
  3196. match, err = argon2id.ComparePasswordAndHash(password, user.Password)
  3197. if err != nil {
  3198. providerLog(logger.LevelError, "error comparing password with argon hash: %v", err)
  3199. return match, err
  3200. }
  3201. updatePwd = config.PasswordHashing.Algo != HashingAlgoArgon2ID
  3202. case util.IsStringPrefixInSlice(user.Password, unixPwdPrefixes):
  3203. match, err = compareUnixPasswordAndHash(user, password)
  3204. if err != nil {
  3205. return match, err
  3206. }
  3207. case util.IsStringPrefixInSlice(user.Password, pbkdfPwdPrefixes):
  3208. match, err = comparePbkdf2PasswordAndHash(password, user.Password)
  3209. if err != nil {
  3210. return match, err
  3211. }
  3212. case util.IsStringPrefixInSlice(user.Password, digestPwdPrefixes):
  3213. match = compareDigestPasswordAndHash(user, password)
  3214. }
  3215. if err == nil && match {
  3216. cachedUserPasswords.Add(user.Username, password, user.Password)
  3217. if updatePwd {
  3218. convertUserPassword(user.Username, password)
  3219. }
  3220. }
  3221. return match, err
  3222. }
  3223. func convertUserPassword(username, plainPwd string) {
  3224. hashedPwd, err := hashPlainPassword(plainPwd)
  3225. if err == nil {
  3226. err = provider.updateUserPassword(username, hashedPwd)
  3227. }
  3228. if err != nil {
  3229. providerLog(logger.LevelWarn, "unable to convert password for user %s: %v", username, err)
  3230. } else {
  3231. providerLog(logger.LevelDebug, "password converted for user %s", username)
  3232. }
  3233. }
  3234. func checkUserAndTLSCertificate(user *User, protocol string, tlsCert *x509.Certificate) (User, error) {
  3235. err := user.LoadAndApplyGroupSettings()
  3236. if err != nil {
  3237. return *user, err
  3238. }
  3239. err = user.CheckLoginConditions()
  3240. if err != nil {
  3241. return *user, err
  3242. }
  3243. switch protocol {
  3244. case protocolFTP, protocolWebDAV:
  3245. for _, cert := range user.Filters.TLSCerts {
  3246. derBlock, _ := pem.Decode(util.StringToBytes(cert))
  3247. if derBlock != nil && bytes.Equal(derBlock.Bytes, tlsCert.Raw) {
  3248. return *user, nil
  3249. }
  3250. }
  3251. if user.Filters.TLSUsername == sdk.TLSUsernameCN {
  3252. if user.Username == tlsCert.Subject.CommonName {
  3253. return *user, nil
  3254. }
  3255. return *user, fmt.Errorf("CN %q does not match username %q", tlsCert.Subject.CommonName, user.Username)
  3256. }
  3257. return *user, errors.New("TLS certificate is not valid")
  3258. default:
  3259. return *user, fmt.Errorf("certificate authentication is not supported for protocol %v", protocol)
  3260. }
  3261. }
  3262. func checkUserAndPass(user *User, password, ip, protocol string) (User, error) {
  3263. err := user.LoadAndApplyGroupSettings()
  3264. if err != nil {
  3265. return *user, err
  3266. }
  3267. err = user.CheckLoginConditions()
  3268. if err != nil {
  3269. return *user, err
  3270. }
  3271. if protocol != protocolHTTP && user.MustChangePassword() {
  3272. return *user, errors.New("login not allowed, password change required")
  3273. }
  3274. if user.Filters.IsAnonymous {
  3275. user.setAnonymousSettings()
  3276. return *user, nil
  3277. }
  3278. password, err = checkUserPasscode(user, password, protocol)
  3279. if err != nil {
  3280. return *user, ErrInvalidCredentials
  3281. }
  3282. if user.Password == "" || password == "" {
  3283. return *user, errors.New("credentials cannot be null or empty")
  3284. }
  3285. if !user.Filters.Hooks.CheckPasswordDisabled {
  3286. hookResponse, err := executeCheckPasswordHook(user.Username, password, ip, protocol)
  3287. if err != nil {
  3288. providerLog(logger.LevelDebug, "error executing check password hook for user %q, ip %v, protocol %v: %v",
  3289. user.Username, ip, protocol, err)
  3290. return *user, errors.New("unable to check credentials")
  3291. }
  3292. switch hookResponse.Status {
  3293. case -1:
  3294. // no hook configured
  3295. case 1:
  3296. providerLog(logger.LevelDebug, "password accepted by check password hook for user %q, ip %v, protocol %v",
  3297. user.Username, ip, protocol)
  3298. return *user, nil
  3299. case 2:
  3300. providerLog(logger.LevelDebug, "partial success from check password hook for user %q, ip %v, protocol %v",
  3301. user.Username, ip, protocol)
  3302. password = hookResponse.ToVerify
  3303. default:
  3304. providerLog(logger.LevelDebug, "password rejected by check password hook for user %q, ip %v, protocol %v, status: %v",
  3305. user.Username, ip, protocol, hookResponse.Status)
  3306. return *user, ErrInvalidCredentials
  3307. }
  3308. }
  3309. match, err := isPasswordOK(user, password)
  3310. if !match {
  3311. err = ErrInvalidCredentials
  3312. }
  3313. return *user, err
  3314. }
  3315. func checkUserPasscode(user *User, password, protocol string) (string, error) {
  3316. if user.Filters.TOTPConfig.Enabled {
  3317. switch protocol {
  3318. case protocolFTP:
  3319. if slices.Contains(user.Filters.TOTPConfig.Protocols, protocol) {
  3320. // the TOTP passcode has six digits
  3321. pwdLen := len(password)
  3322. if pwdLen < 7 {
  3323. providerLog(logger.LevelDebug, "password len %v is too short to contain a passcode, user %q, protocol %v",
  3324. pwdLen, user.Username, protocol)
  3325. return "", util.NewValidationError("password too short, cannot contain the passcode")
  3326. }
  3327. err := user.Filters.TOTPConfig.Secret.TryDecrypt()
  3328. if err != nil {
  3329. providerLog(logger.LevelError, "unable to decrypt TOTP secret for user %q, protocol %v, err: %v",
  3330. user.Username, protocol, err)
  3331. return "", err
  3332. }
  3333. pwd := password[0:(pwdLen - 6)]
  3334. passcode := password[(pwdLen - 6):]
  3335. match, err := mfa.ValidateTOTPPasscode(user.Filters.TOTPConfig.ConfigName, passcode,
  3336. user.Filters.TOTPConfig.Secret.GetPayload())
  3337. if !match || err != nil {
  3338. providerLog(logger.LevelWarn, "invalid passcode for user %q, protocol %v, err: %v",
  3339. user.Username, protocol, err)
  3340. return "", util.NewValidationError("invalid passcode")
  3341. }
  3342. return pwd, nil
  3343. }
  3344. }
  3345. }
  3346. return password, nil
  3347. }
  3348. func checkUserAndPubKey(user *User, pubKey []byte, isSSHCert bool) (User, string, error) {
  3349. err := user.LoadAndApplyGroupSettings()
  3350. if err != nil {
  3351. return *user, "", err
  3352. }
  3353. err = user.CheckLoginConditions()
  3354. if err != nil {
  3355. return *user, "", err
  3356. }
  3357. if isSSHCert {
  3358. return *user, "", nil
  3359. }
  3360. if len(user.PublicKeys) == 0 {
  3361. return *user, "", ErrInvalidCredentials
  3362. }
  3363. for idx, key := range user.PublicKeys {
  3364. storedKey, comment, _, _, err := ssh.ParseAuthorizedKey(util.StringToBytes(key))
  3365. if err != nil {
  3366. providerLog(logger.LevelError, "error parsing stored public key %d for user %s: %v", idx, user.Username, err)
  3367. return *user, "", err
  3368. }
  3369. if bytes.Equal(storedKey.Marshal(), pubKey) {
  3370. return *user, fmt.Sprintf("%s:%s", ssh.FingerprintSHA256(storedKey), comment), nil
  3371. }
  3372. }
  3373. return *user, "", ErrInvalidCredentials
  3374. }
  3375. func compareDigestPasswordAndHash(user *User, password string) bool {
  3376. if strings.HasPrefix(user.Password, md5DigestPwdPrefix) {
  3377. h := md5.New()
  3378. h.Write([]byte(password))
  3379. return fmt.Sprintf("%s%x", md5DigestPwdPrefix, h.Sum(nil)) == user.Password
  3380. }
  3381. if strings.HasPrefix(user.Password, sha256DigestPwdPrefix) {
  3382. h := sha256.New()
  3383. h.Write([]byte(password))
  3384. return fmt.Sprintf("%s%x", sha256DigestPwdPrefix, h.Sum(nil)) == user.Password
  3385. }
  3386. if strings.HasPrefix(user.Password, sha512DigestPwdPrefix) {
  3387. h := sha512.New()
  3388. h.Write([]byte(password))
  3389. return fmt.Sprintf("%s%x", sha512DigestPwdPrefix, h.Sum(nil)) == user.Password
  3390. }
  3391. return false
  3392. }
  3393. func compareUnixPasswordAndHash(user *User, password string) (bool, error) {
  3394. if strings.HasPrefix(user.Password, yescryptPwdPrefix) {
  3395. return compareYescryptPassword(user.Password, password)
  3396. }
  3397. var crypter crypt.Crypter
  3398. if strings.HasPrefix(user.Password, sha512cryptPwdPrefix) {
  3399. crypter = sha512_crypt.New()
  3400. } else if strings.HasPrefix(user.Password, sha256cryptPwdPrefix) {
  3401. crypter = sha256_crypt.New()
  3402. } else if strings.HasPrefix(user.Password, md5cryptPwdPrefix) {
  3403. crypter = md5_crypt.New()
  3404. } else if strings.HasPrefix(user.Password, md5cryptApr1PwdPrefix) {
  3405. crypter = apr1_crypt.New()
  3406. } else {
  3407. return false, errors.New("unix crypt: invalid or unsupported hash format")
  3408. }
  3409. if err := crypter.Verify(user.Password, []byte(password)); err != nil {
  3410. return false, err
  3411. }
  3412. return true, nil
  3413. }
  3414. func comparePbkdf2PasswordAndHash(password, hashedPassword string) (bool, error) {
  3415. vals := strings.Split(hashedPassword, "$")
  3416. if len(vals) != 5 {
  3417. return false, fmt.Errorf("pbkdf2: hash is not in the correct format")
  3418. }
  3419. iterations, err := strconv.Atoi(vals[2])
  3420. if err != nil {
  3421. return false, err
  3422. }
  3423. expected, err := base64.StdEncoding.DecodeString(vals[4])
  3424. if err != nil {
  3425. return false, err
  3426. }
  3427. var salt []byte
  3428. if util.IsStringPrefixInSlice(hashedPassword, pbkdfPwdB64SaltPrefixes) {
  3429. salt, err = base64.StdEncoding.DecodeString(vals[3])
  3430. if err != nil {
  3431. return false, err
  3432. }
  3433. } else {
  3434. salt = []byte(vals[3])
  3435. }
  3436. var hashFunc func() hash.Hash
  3437. if strings.HasPrefix(hashedPassword, pbkdf2SHA256Prefix) || strings.HasPrefix(hashedPassword, pbkdf2SHA256B64SaltPrefix) {
  3438. hashFunc = sha256.New
  3439. } else if strings.HasPrefix(hashedPassword, pbkdf2SHA512Prefix) {
  3440. hashFunc = sha512.New
  3441. } else if strings.HasPrefix(hashedPassword, pbkdf2SHA1Prefix) {
  3442. hashFunc = sha1.New
  3443. } else {
  3444. return false, fmt.Errorf("pbkdf2: invalid or unsupported hash format %v", vals[1])
  3445. }
  3446. df := pbkdf2.Key([]byte(password), salt, iterations, len(expected), hashFunc)
  3447. return subtle.ConstantTimeCompare(df, expected) == 1, nil
  3448. }
  3449. func getSSLMode() string {
  3450. switch config.Driver {
  3451. case PGSQLDataProviderName, CockroachDataProviderName:
  3452. switch config.SSLMode {
  3453. case 0:
  3454. return "disable"
  3455. case 1:
  3456. return "require"
  3457. case 2:
  3458. return "verify-ca"
  3459. case 3:
  3460. return "verify-full"
  3461. case 4:
  3462. return "prefer"
  3463. case 5:
  3464. return "allow"
  3465. }
  3466. case MySQLDataProviderName:
  3467. if config.requireCustomTLSForMySQL() {
  3468. return "custom"
  3469. }
  3470. switch config.SSLMode {
  3471. case 0:
  3472. return "false"
  3473. case 1:
  3474. return "true"
  3475. case 2:
  3476. return "skip-verify"
  3477. case 3:
  3478. return "preferred"
  3479. }
  3480. }
  3481. return ""
  3482. }
  3483. func terminateInteractiveAuthProgram(cmd *exec.Cmd, isFinished bool) {
  3484. if isFinished {
  3485. return
  3486. }
  3487. providerLog(logger.LevelInfo, "kill interactive auth program after an unexpected error")
  3488. err := cmd.Process.Kill()
  3489. if err != nil {
  3490. providerLog(logger.LevelDebug, "error killing interactive auth program: %v", err)
  3491. }
  3492. }
  3493. func sendKeyboardAuthHTTPReq(url string, request *plugin.KeyboardAuthRequest) (*plugin.KeyboardAuthResponse, error) {
  3494. reqAsJSON, err := json.Marshal(request)
  3495. if err != nil {
  3496. providerLog(logger.LevelError, "error serializing keyboard interactive auth request: %v", err)
  3497. return nil, err
  3498. }
  3499. resp, err := httpclient.Post(url, "application/json", bytes.NewBuffer(reqAsJSON))
  3500. if err != nil {
  3501. providerLog(logger.LevelError, "error getting keyboard interactive auth hook HTTP response: %v", err)
  3502. return nil, err
  3503. }
  3504. defer resp.Body.Close()
  3505. if resp.StatusCode != http.StatusOK {
  3506. return nil, fmt.Errorf("wrong keyboard interactive auth http status code: %v, expected 200", resp.StatusCode)
  3507. }
  3508. var response plugin.KeyboardAuthResponse
  3509. err = render.DecodeJSON(resp.Body, &response)
  3510. return &response, err
  3511. }
  3512. func doBuiltinKeyboardInteractiveAuth(user *User, client ssh.KeyboardInteractiveChallenge,
  3513. ip, protocol string, isPartialAuth bool,
  3514. ) (int, error) {
  3515. if err := user.LoadAndApplyGroupSettings(); err != nil {
  3516. return 0, err
  3517. }
  3518. hasSecondFactor := user.Filters.TOTPConfig.Enabled && slices.Contains(user.Filters.TOTPConfig.Protocols, protocolSSH)
  3519. if !isPartialAuth || !hasSecondFactor {
  3520. answers, err := client("", "", []string{"Password: "}, []bool{false})
  3521. if err != nil {
  3522. return 0, err
  3523. }
  3524. if len(answers) != 1 {
  3525. return 0, fmt.Errorf("unexpected number of answers: %d", len(answers))
  3526. }
  3527. _, err = checkUserAndPass(user, answers[0], ip, protocol)
  3528. if err != nil {
  3529. return 0, err
  3530. }
  3531. }
  3532. return checkKeyboardInteractiveSecondFactor(user, client, protocol)
  3533. }
  3534. func checkKeyboardInteractiveSecondFactor(user *User, client ssh.KeyboardInteractiveChallenge, protocol string) (int, error) {
  3535. if !user.Filters.TOTPConfig.Enabled || !slices.Contains(user.Filters.TOTPConfig.Protocols, protocolSSH) {
  3536. return 1, nil
  3537. }
  3538. err := user.Filters.TOTPConfig.Secret.TryDecrypt()
  3539. if err != nil {
  3540. providerLog(logger.LevelError, "unable to decrypt TOTP secret for user %q, protocol %v, err: %v",
  3541. user.Username, protocol, err)
  3542. return 0, err
  3543. }
  3544. answers, err := client("", "", []string{"Authentication code: "}, []bool{false})
  3545. if err != nil {
  3546. return 0, err
  3547. }
  3548. if len(answers) != 1 {
  3549. return 0, fmt.Errorf("unexpected number of answers: %v", len(answers))
  3550. }
  3551. match, err := mfa.ValidateTOTPPasscode(user.Filters.TOTPConfig.ConfigName, answers[0],
  3552. user.Filters.TOTPConfig.Secret.GetPayload())
  3553. if !match || err != nil {
  3554. providerLog(logger.LevelWarn, "invalid passcode for user %q, protocol %v, err: %v",
  3555. user.Username, protocol, err)
  3556. return 0, util.NewValidationError("invalid passcode")
  3557. }
  3558. return 1, nil
  3559. }
  3560. func executeKeyboardInteractivePlugin(user *User, client ssh.KeyboardInteractiveChallenge, ip, protocol string) (int, error) {
  3561. authResult := 0
  3562. requestID := xid.New().String()
  3563. authStep := 1
  3564. req := &plugin.KeyboardAuthRequest{
  3565. Username: user.Username,
  3566. IP: ip,
  3567. Password: user.Password,
  3568. RequestID: requestID,
  3569. Step: authStep,
  3570. }
  3571. var response *plugin.KeyboardAuthResponse
  3572. var err error
  3573. for {
  3574. response, err = plugin.Handler.ExecuteKeyboardInteractiveStep(req)
  3575. if err != nil {
  3576. return authResult, err
  3577. }
  3578. if response.AuthResult != 0 {
  3579. return response.AuthResult, err
  3580. }
  3581. if err = response.Validate(); err != nil {
  3582. providerLog(logger.LevelInfo, "invalid response from keyboard interactive plugin: %v", err)
  3583. return authResult, err
  3584. }
  3585. answers, err := getKeyboardInteractiveAnswers(client, response, user, ip, protocol)
  3586. if err != nil {
  3587. return authResult, err
  3588. }
  3589. authStep++
  3590. req = &plugin.KeyboardAuthRequest{
  3591. RequestID: requestID,
  3592. Step: authStep,
  3593. Username: user.Username,
  3594. Password: user.Password,
  3595. Answers: answers,
  3596. Questions: response.Questions,
  3597. }
  3598. }
  3599. }
  3600. func executeKeyboardInteractiveHTTPHook(user *User, authHook string, client ssh.KeyboardInteractiveChallenge, ip, protocol string) (int, error) {
  3601. authResult := 0
  3602. requestID := xid.New().String()
  3603. authStep := 1
  3604. req := &plugin.KeyboardAuthRequest{
  3605. Username: user.Username,
  3606. IP: ip,
  3607. Password: user.Password,
  3608. RequestID: requestID,
  3609. Step: authStep,
  3610. }
  3611. var response *plugin.KeyboardAuthResponse
  3612. var err error
  3613. for {
  3614. response, err = sendKeyboardAuthHTTPReq(authHook, req)
  3615. if err != nil {
  3616. return authResult, err
  3617. }
  3618. if response.AuthResult != 0 {
  3619. return response.AuthResult, err
  3620. }
  3621. if err = response.Validate(); err != nil {
  3622. providerLog(logger.LevelInfo, "invalid response from keyboard interactive http hook: %v", err)
  3623. return authResult, err
  3624. }
  3625. answers, err := getKeyboardInteractiveAnswers(client, response, user, ip, protocol)
  3626. if err != nil {
  3627. return authResult, err
  3628. }
  3629. authStep++
  3630. req = &plugin.KeyboardAuthRequest{
  3631. RequestID: requestID,
  3632. Step: authStep,
  3633. Username: user.Username,
  3634. Password: user.Password,
  3635. Answers: answers,
  3636. Questions: response.Questions,
  3637. }
  3638. }
  3639. }
  3640. func getKeyboardInteractiveAnswers(client ssh.KeyboardInteractiveChallenge, response *plugin.KeyboardAuthResponse,
  3641. user *User, ip, protocol string,
  3642. ) ([]string, error) {
  3643. questions := response.Questions
  3644. answers, err := client("", response.Instruction, questions, response.Echos)
  3645. if err != nil {
  3646. providerLog(logger.LevelInfo, "error getting interactive auth client response: %v", err)
  3647. return answers, err
  3648. }
  3649. if len(answers) != len(questions) {
  3650. err = fmt.Errorf("client answers does not match questions, expected: %v actual: %v", questions, answers)
  3651. providerLog(logger.LevelInfo, "keyboard interactive auth error: %v", err)
  3652. return answers, err
  3653. }
  3654. if len(answers) == 1 && response.CheckPwd > 0 {
  3655. if response.CheckPwd == 2 {
  3656. if !user.Filters.TOTPConfig.Enabled || !slices.Contains(user.Filters.TOTPConfig.Protocols, protocolSSH) {
  3657. providerLog(logger.LevelInfo, "keyboard interactive auth error: unable to check TOTP passcode, TOTP is not enabled for user %q",
  3658. user.Username)
  3659. return answers, errors.New("TOTP not enabled for SSH protocol")
  3660. }
  3661. err := user.Filters.TOTPConfig.Secret.TryDecrypt()
  3662. if err != nil {
  3663. providerLog(logger.LevelError, "unable to decrypt TOTP secret for user %q, protocol %v, err: %v",
  3664. user.Username, protocol, err)
  3665. return answers, fmt.Errorf("unable to decrypt TOTP secret: %w", err)
  3666. }
  3667. match, err := mfa.ValidateTOTPPasscode(user.Filters.TOTPConfig.ConfigName, answers[0],
  3668. user.Filters.TOTPConfig.Secret.GetPayload())
  3669. if !match || err != nil {
  3670. providerLog(logger.LevelInfo, "keyboard interactive auth error: unable to validate passcode for user %q, match? %v, err: %v",
  3671. user.Username, match, err)
  3672. return answers, errors.New("unable to validate TOTP passcode")
  3673. }
  3674. } else {
  3675. _, err = checkUserAndPass(user, answers[0], ip, protocol)
  3676. providerLog(logger.LevelInfo, "interactive auth hook requested password validation for user %q, validation error: %v",
  3677. user.Username, err)
  3678. if err != nil {
  3679. return answers, err
  3680. }
  3681. }
  3682. answers[0] = "OK"
  3683. }
  3684. return answers, err
  3685. }
  3686. func handleProgramInteractiveQuestions(client ssh.KeyboardInteractiveChallenge, response *plugin.KeyboardAuthResponse,
  3687. user *User, stdin io.WriteCloser, ip, protocol string,
  3688. ) error {
  3689. answers, err := getKeyboardInteractiveAnswers(client, response, user, ip, protocol)
  3690. if err != nil {
  3691. return err
  3692. }
  3693. for _, answer := range answers {
  3694. if runtime.GOOS == "windows" {
  3695. answer += "\r"
  3696. }
  3697. answer += "\n"
  3698. _, err = stdin.Write([]byte(answer))
  3699. if err != nil {
  3700. providerLog(logger.LevelError, "unable to write client answer to keyboard interactive program: %v", err)
  3701. return err
  3702. }
  3703. }
  3704. return nil
  3705. }
  3706. func executeKeyboardInteractiveProgram(user *User, authHook string, client ssh.KeyboardInteractiveChallenge, ip, protocol string) (int, error) {
  3707. authResult := 0
  3708. timeout, env, args := command.GetConfig(authHook, command.HookKeyboardInteractive)
  3709. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  3710. defer cancel()
  3711. cmd := exec.CommandContext(ctx, authHook, args...)
  3712. cmd.Env = append(env,
  3713. fmt.Sprintf("SFTPGO_AUTHD_USERNAME=%s", user.Username),
  3714. fmt.Sprintf("SFTPGO_AUTHD_IP=%s", ip),
  3715. fmt.Sprintf("SFTPGO_AUTHD_PASSWORD=%s", user.Password))
  3716. stdout, err := cmd.StdoutPipe()
  3717. if err != nil {
  3718. return authResult, err
  3719. }
  3720. stdin, err := cmd.StdinPipe()
  3721. if err != nil {
  3722. return authResult, err
  3723. }
  3724. err = cmd.Start()
  3725. if err != nil {
  3726. return authResult, err
  3727. }
  3728. var once sync.Once
  3729. scanner := bufio.NewScanner(stdout)
  3730. for scanner.Scan() {
  3731. var response plugin.KeyboardAuthResponse
  3732. err = json.Unmarshal(scanner.Bytes(), &response)
  3733. if err != nil {
  3734. providerLog(logger.LevelInfo, "interactive auth error parsing response: %v", err)
  3735. once.Do(func() { terminateInteractiveAuthProgram(cmd, false) })
  3736. break
  3737. }
  3738. if response.AuthResult != 0 {
  3739. authResult = response.AuthResult
  3740. break
  3741. }
  3742. if err = response.Validate(); err != nil {
  3743. providerLog(logger.LevelInfo, "invalid response from keyboard interactive program: %v", err)
  3744. once.Do(func() { terminateInteractiveAuthProgram(cmd, false) })
  3745. break
  3746. }
  3747. go func() {
  3748. err := handleProgramInteractiveQuestions(client, &response, user, stdin, ip, protocol)
  3749. if err != nil {
  3750. once.Do(func() { terminateInteractiveAuthProgram(cmd, false) })
  3751. }
  3752. }()
  3753. }
  3754. stdin.Close()
  3755. once.Do(func() { terminateInteractiveAuthProgram(cmd, true) })
  3756. go func() {
  3757. _, err := cmd.Process.Wait()
  3758. if err != nil {
  3759. providerLog(logger.LevelWarn, "error waiting for %q process to exit: %v", authHook, err)
  3760. }
  3761. }()
  3762. return authResult, err
  3763. }
  3764. func doKeyboardInteractiveAuth(user *User, authHook string, client ssh.KeyboardInteractiveChallenge,
  3765. ip, protocol string, isPartialAuth bool,
  3766. ) (User, error) {
  3767. if err := user.LoadAndApplyGroupSettings(); err != nil {
  3768. return *user, err
  3769. }
  3770. var authResult int
  3771. var err error
  3772. if !user.Filters.Hooks.ExternalAuthDisabled {
  3773. if plugin.Handler.HasAuthScope(plugin.AuthScopeKeyboardInteractive) {
  3774. authResult, err = executeKeyboardInteractivePlugin(user, client, ip, protocol)
  3775. if authResult == 1 && err == nil {
  3776. authResult, err = checkKeyboardInteractiveSecondFactor(user, client, protocol)
  3777. }
  3778. } else if authHook != "" {
  3779. if strings.HasPrefix(authHook, "http") {
  3780. authResult, err = executeKeyboardInteractiveHTTPHook(user, authHook, client, ip, protocol)
  3781. } else {
  3782. authResult, err = executeKeyboardInteractiveProgram(user, authHook, client, ip, protocol)
  3783. }
  3784. } else {
  3785. authResult, err = doBuiltinKeyboardInteractiveAuth(user, client, ip, protocol, isPartialAuth)
  3786. }
  3787. } else {
  3788. authResult, err = doBuiltinKeyboardInteractiveAuth(user, client, ip, protocol, isPartialAuth)
  3789. }
  3790. if err != nil {
  3791. return *user, err
  3792. }
  3793. if authResult != 1 {
  3794. return *user, fmt.Errorf("keyboard interactive auth failed, result: %v", authResult)
  3795. }
  3796. err = user.CheckLoginConditions()
  3797. if err != nil {
  3798. return *user, err
  3799. }
  3800. return *user, nil
  3801. }
  3802. func isCheckPasswordHookDefined(protocol string) bool {
  3803. if config.CheckPasswordHook == "" {
  3804. return false
  3805. }
  3806. if config.CheckPasswordScope == 0 {
  3807. return true
  3808. }
  3809. switch protocol {
  3810. case protocolSSH:
  3811. return config.CheckPasswordScope&1 != 0
  3812. case protocolFTP:
  3813. return config.CheckPasswordScope&2 != 0
  3814. case protocolWebDAV:
  3815. return config.CheckPasswordScope&4 != 0
  3816. default:
  3817. return false
  3818. }
  3819. }
  3820. func getPasswordHookResponse(username, password, ip, protocol string) ([]byte, error) {
  3821. if strings.HasPrefix(config.CheckPasswordHook, "http") {
  3822. var result []byte
  3823. req := checkPasswordRequest{
  3824. Username: username,
  3825. Password: password,
  3826. IP: ip,
  3827. Protocol: protocol,
  3828. }
  3829. reqAsJSON, err := json.Marshal(req)
  3830. if err != nil {
  3831. return result, err
  3832. }
  3833. resp, err := httpclient.Post(config.CheckPasswordHook, "application/json", bytes.NewBuffer(reqAsJSON))
  3834. if err != nil {
  3835. providerLog(logger.LevelError, "error getting check password hook response: %v", err)
  3836. return result, err
  3837. }
  3838. defer resp.Body.Close()
  3839. if resp.StatusCode != http.StatusOK {
  3840. return result, fmt.Errorf("wrong http status code from chek password hook: %v, expected 200", resp.StatusCode)
  3841. }
  3842. return io.ReadAll(io.LimitReader(resp.Body, maxHookResponseSize))
  3843. }
  3844. timeout, env, args := command.GetConfig(config.CheckPasswordHook, command.HookCheckPassword)
  3845. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  3846. defer cancel()
  3847. cmd := exec.CommandContext(ctx, config.CheckPasswordHook, args...)
  3848. cmd.Env = append(env,
  3849. fmt.Sprintf("SFTPGO_AUTHD_USERNAME=%s", username),
  3850. fmt.Sprintf("SFTPGO_AUTHD_PASSWORD=%s", password),
  3851. fmt.Sprintf("SFTPGO_AUTHD_IP=%s", ip),
  3852. fmt.Sprintf("SFTPGO_AUTHD_PROTOCOL=%s", protocol),
  3853. )
  3854. return cmd.Output()
  3855. }
  3856. func executeCheckPasswordHook(username, password, ip, protocol string) (checkPasswordResponse, error) {
  3857. var response checkPasswordResponse
  3858. if !isCheckPasswordHookDefined(protocol) {
  3859. response.Status = -1
  3860. return response, nil
  3861. }
  3862. startTime := time.Now()
  3863. out, err := getPasswordHookResponse(username, password, ip, protocol)
  3864. providerLog(logger.LevelDebug, "check password hook executed, error: %v, elapsed: %v", err, time.Since(startTime))
  3865. if err != nil {
  3866. return response, err
  3867. }
  3868. err = json.Unmarshal(out, &response)
  3869. return response, err
  3870. }
  3871. func getPreLoginHookResponse(loginMethod, ip, protocol string, userAsJSON []byte) ([]byte, error) {
  3872. if strings.HasPrefix(config.PreLoginHook, "http") {
  3873. var url *url.URL
  3874. var result []byte
  3875. url, err := url.Parse(config.PreLoginHook)
  3876. if err != nil {
  3877. providerLog(logger.LevelError, "invalid url for pre-login hook %q, error: %v", config.PreLoginHook, err)
  3878. return result, err
  3879. }
  3880. q := url.Query()
  3881. q.Add("login_method", loginMethod)
  3882. q.Add("ip", ip)
  3883. q.Add("protocol", protocol)
  3884. url.RawQuery = q.Encode()
  3885. resp, err := httpclient.Post(url.String(), "application/json", bytes.NewBuffer(userAsJSON))
  3886. if err != nil {
  3887. providerLog(logger.LevelWarn, "error getting pre-login hook response: %v", err)
  3888. return result, err
  3889. }
  3890. defer resp.Body.Close()
  3891. if resp.StatusCode == http.StatusNoContent {
  3892. return result, nil
  3893. }
  3894. if resp.StatusCode != http.StatusOK {
  3895. return result, fmt.Errorf("wrong pre-login hook http status code: %v, expected 200", resp.StatusCode)
  3896. }
  3897. return io.ReadAll(io.LimitReader(resp.Body, maxHookResponseSize))
  3898. }
  3899. timeout, env, args := command.GetConfig(config.PreLoginHook, command.HookPreLogin)
  3900. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  3901. defer cancel()
  3902. cmd := exec.CommandContext(ctx, config.PreLoginHook, args...)
  3903. cmd.Env = append(env,
  3904. fmt.Sprintf("SFTPGO_LOGIND_USER=%s", userAsJSON),
  3905. fmt.Sprintf("SFTPGO_LOGIND_METHOD=%s", loginMethod),
  3906. fmt.Sprintf("SFTPGO_LOGIND_IP=%s", ip),
  3907. fmt.Sprintf("SFTPGO_LOGIND_PROTOCOL=%s", protocol),
  3908. )
  3909. return cmd.Output()
  3910. }
  3911. func executePreLoginHook(username, loginMethod, ip, protocol string, oidcTokenFields *map[string]any) (User, error) {
  3912. u, mergedUser, userAsJSON, err := getUserAndJSONForHook(username, oidcTokenFields)
  3913. if err != nil {
  3914. return u, err
  3915. }
  3916. if mergedUser.Filters.Hooks.PreLoginDisabled {
  3917. return u, nil
  3918. }
  3919. startTime := time.Now()
  3920. out, err := getPreLoginHookResponse(loginMethod, ip, protocol, userAsJSON)
  3921. if err != nil {
  3922. return u, fmt.Errorf("pre-login hook error: %v, username %q, ip %v, protocol %v elapsed %v",
  3923. err, username, ip, protocol, time.Since(startTime))
  3924. }
  3925. providerLog(logger.LevelDebug, "pre-login hook completed, elapsed: %s", time.Since(startTime))
  3926. if util.IsByteArrayEmpty(out) {
  3927. providerLog(logger.LevelDebug, "empty response from pre-login hook, no modification requested for user %q id: %d",
  3928. username, u.ID)
  3929. if u.ID == 0 {
  3930. return u, util.NewRecordNotFoundError(fmt.Sprintf("username %q does not exist", username))
  3931. }
  3932. return u, nil
  3933. }
  3934. userID := u.ID
  3935. userUsedQuotaSize := u.UsedQuotaSize
  3936. userUsedQuotaFiles := u.UsedQuotaFiles
  3937. userUsedDownloadTransfer := u.UsedDownloadDataTransfer
  3938. userUsedUploadTransfer := u.UsedUploadDataTransfer
  3939. userLastQuotaUpdate := u.LastQuotaUpdate
  3940. userLastLogin := u.LastLogin
  3941. userFirstDownload := u.FirstDownload
  3942. userFirstUpload := u.FirstUpload
  3943. userLastPwdChange := u.LastPasswordChange
  3944. userCreatedAt := u.CreatedAt
  3945. totpConfig := u.Filters.TOTPConfig
  3946. recoveryCodes := u.Filters.RecoveryCodes
  3947. err = json.Unmarshal(out, &u)
  3948. if err != nil {
  3949. return u, fmt.Errorf("invalid pre-login hook response %q, error: %v", out, err)
  3950. }
  3951. u.ID = userID
  3952. u.UsedQuotaSize = userUsedQuotaSize
  3953. u.UsedQuotaFiles = userUsedQuotaFiles
  3954. u.UsedUploadDataTransfer = userUsedUploadTransfer
  3955. u.UsedDownloadDataTransfer = userUsedDownloadTransfer
  3956. u.LastQuotaUpdate = userLastQuotaUpdate
  3957. u.LastLogin = userLastLogin
  3958. u.LastPasswordChange = userLastPwdChange
  3959. u.FirstDownload = userFirstDownload
  3960. u.FirstUpload = userFirstUpload
  3961. u.CreatedAt = userCreatedAt
  3962. if userID == 0 {
  3963. err = provider.addUser(&u)
  3964. } else {
  3965. u.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
  3966. // preserve TOTP config and recovery codes
  3967. u.Filters.TOTPConfig = totpConfig
  3968. u.Filters.RecoveryCodes = recoveryCodes
  3969. err = provider.updateUser(&u)
  3970. if err == nil {
  3971. webDAVUsersCache.swap(&u, "")
  3972. }
  3973. }
  3974. if err != nil {
  3975. return u, err
  3976. }
  3977. providerLog(logger.LevelDebug, "user %q added/updated from pre-login hook response, id: %d", username, userID)
  3978. if userID == 0 {
  3979. return provider.userExists(username, "")
  3980. }
  3981. return u, nil
  3982. }
  3983. // ExecutePostLoginHook executes the post login hook if defined
  3984. func ExecutePostLoginHook(user *User, loginMethod, ip, protocol string, err error) {
  3985. if config.PostLoginHook == "" {
  3986. return
  3987. }
  3988. if config.PostLoginScope == 1 && err == nil {
  3989. return
  3990. }
  3991. if config.PostLoginScope == 2 && err != nil {
  3992. return
  3993. }
  3994. go func() {
  3995. actionsConcurrencyGuard <- struct{}{}
  3996. defer func() {
  3997. <-actionsConcurrencyGuard
  3998. }()
  3999. status := "0"
  4000. if err == nil {
  4001. status = "1"
  4002. }
  4003. user.PrepareForRendering()
  4004. userAsJSON, err := json.Marshal(user)
  4005. if err != nil {
  4006. providerLog(logger.LevelError, "error serializing user in post login hook: %v", err)
  4007. return
  4008. }
  4009. if strings.HasPrefix(config.PostLoginHook, "http") {
  4010. var url *url.URL
  4011. url, err := url.Parse(config.PostLoginHook)
  4012. if err != nil {
  4013. providerLog(logger.LevelDebug, "Invalid post-login hook %q", config.PostLoginHook)
  4014. return
  4015. }
  4016. q := url.Query()
  4017. q.Add("login_method", loginMethod)
  4018. q.Add("ip", ip)
  4019. q.Add("protocol", protocol)
  4020. q.Add("status", status)
  4021. url.RawQuery = q.Encode()
  4022. startTime := time.Now()
  4023. respCode := 0
  4024. resp, err := httpclient.RetryablePost(url.String(), "application/json", bytes.NewBuffer(userAsJSON))
  4025. if err == nil {
  4026. respCode = resp.StatusCode
  4027. resp.Body.Close()
  4028. }
  4029. providerLog(logger.LevelDebug, "post login hook executed for user %q, ip %v, protocol %v, response code: %v, elapsed: %v err: %v",
  4030. user.Username, ip, protocol, respCode, time.Since(startTime), err)
  4031. return
  4032. }
  4033. timeout, env, args := command.GetConfig(config.PostLoginHook, command.HookPostLogin)
  4034. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  4035. defer cancel()
  4036. cmd := exec.CommandContext(ctx, config.PostLoginHook, args...)
  4037. cmd.Env = append(env,
  4038. fmt.Sprintf("SFTPGO_LOGIND_USER=%s", userAsJSON),
  4039. fmt.Sprintf("SFTPGO_LOGIND_IP=%s", ip),
  4040. fmt.Sprintf("SFTPGO_LOGIND_METHOD=%s", loginMethod),
  4041. fmt.Sprintf("SFTPGO_LOGIND_STATUS=%s", status),
  4042. fmt.Sprintf("SFTPGO_LOGIND_PROTOCOL=%s", protocol))
  4043. startTime := time.Now()
  4044. err = cmd.Run()
  4045. providerLog(logger.LevelDebug, "post login hook executed for user %q, ip %v, protocol %v, elapsed %v err: %v",
  4046. user.Username, ip, protocol, time.Since(startTime), err)
  4047. }()
  4048. }
  4049. func getExternalAuthResponse(username, password, pkey, keyboardInteractive, ip, protocol string, cert *x509.Certificate,
  4050. user User,
  4051. ) ([]byte, error) {
  4052. var tlsCert string
  4053. if cert != nil {
  4054. var err error
  4055. tlsCert, err = util.EncodeTLSCertToPem(cert)
  4056. if err != nil {
  4057. return nil, err
  4058. }
  4059. }
  4060. if strings.HasPrefix(config.ExternalAuthHook, "http") {
  4061. var result []byte
  4062. authRequest := make(map[string]any)
  4063. authRequest["username"] = username
  4064. authRequest["ip"] = ip
  4065. authRequest["password"] = password
  4066. authRequest["public_key"] = pkey
  4067. authRequest["protocol"] = protocol
  4068. authRequest["keyboard_interactive"] = keyboardInteractive
  4069. authRequest["tls_cert"] = tlsCert
  4070. if user.ID > 0 {
  4071. authRequest["user"] = user
  4072. }
  4073. authRequestAsJSON, err := json.Marshal(authRequest)
  4074. if err != nil {
  4075. providerLog(logger.LevelError, "error serializing external auth request: %v", err)
  4076. return result, err
  4077. }
  4078. resp, err := httpclient.Post(config.ExternalAuthHook, "application/json", bytes.NewBuffer(authRequestAsJSON))
  4079. if err != nil {
  4080. providerLog(logger.LevelWarn, "error getting external auth hook HTTP response: %v", err)
  4081. return result, err
  4082. }
  4083. defer resp.Body.Close()
  4084. providerLog(logger.LevelDebug, "external auth hook executed, response code: %v", resp.StatusCode)
  4085. if resp.StatusCode != http.StatusOK {
  4086. return result, fmt.Errorf("wrong external auth http status code: %v, expected 200", resp.StatusCode)
  4087. }
  4088. return io.ReadAll(io.LimitReader(resp.Body, maxHookResponseSize))
  4089. }
  4090. var userAsJSON []byte
  4091. var err error
  4092. if user.ID > 0 {
  4093. userAsJSON, err = json.Marshal(user)
  4094. if err != nil {
  4095. return nil, fmt.Errorf("unable to serialize user as JSON: %w", err)
  4096. }
  4097. }
  4098. timeout, env, args := command.GetConfig(config.ExternalAuthHook, command.HookExternalAuth)
  4099. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  4100. defer cancel()
  4101. cmd := exec.CommandContext(ctx, config.ExternalAuthHook, args...)
  4102. cmd.Env = append(env,
  4103. fmt.Sprintf("SFTPGO_AUTHD_USERNAME=%s", username),
  4104. fmt.Sprintf("SFTPGO_AUTHD_USER=%s", userAsJSON),
  4105. fmt.Sprintf("SFTPGO_AUTHD_IP=%s", ip),
  4106. fmt.Sprintf("SFTPGO_AUTHD_PASSWORD=%s", password),
  4107. fmt.Sprintf("SFTPGO_AUTHD_PUBLIC_KEY=%s", pkey),
  4108. fmt.Sprintf("SFTPGO_AUTHD_PROTOCOL=%s", protocol),
  4109. fmt.Sprintf("SFTPGO_AUTHD_TLS_CERT=%s", strings.ReplaceAll(tlsCert, "\n", "\\n")),
  4110. fmt.Sprintf("SFTPGO_AUTHD_KEYBOARD_INTERACTIVE=%v", keyboardInteractive))
  4111. return cmd.Output()
  4112. }
  4113. func updateUserFromExtAuthResponse(user *User, password, pkey string) {
  4114. if password != "" {
  4115. user.Password = password
  4116. }
  4117. if pkey != "" && !util.IsStringPrefixInSlice(pkey, user.PublicKeys) {
  4118. user.PublicKeys = append(user.PublicKeys, pkey)
  4119. }
  4120. user.LastPasswordChange = 0
  4121. }
  4122. func checkPasswordAfterEmptyExtAuthResponse(user *User, plainPwd, protocol string) error {
  4123. if plainPwd == "" {
  4124. return nil
  4125. }
  4126. match, err := isPasswordOK(user, plainPwd)
  4127. if match && err == nil {
  4128. return nil
  4129. }
  4130. hashedPwd, err := hashPlainPassword(plainPwd)
  4131. if err != nil {
  4132. providerLog(logger.LevelError, "unable to hash password for user %q after empty external response: %v",
  4133. user.Username, err)
  4134. return err
  4135. }
  4136. err = provider.updateUserPassword(user.Username, hashedPwd)
  4137. if err != nil {
  4138. providerLog(logger.LevelError, "unable to update password for user %q after empty external response: %v",
  4139. user.Username, err)
  4140. }
  4141. user.Password = hashedPwd
  4142. cachedUserPasswords.Add(user.Username, plainPwd, user.Password)
  4143. if protocol != protocolWebDAV {
  4144. webDAVUsersCache.swap(user, plainPwd)
  4145. }
  4146. providerLog(logger.LevelDebug, "updated password for user %q after empty external auth response", user.Username)
  4147. return nil
  4148. }
  4149. func doExternalAuth(username, password string, pubKey []byte, keyboardInteractive, ip, protocol string,
  4150. tlsCert *x509.Certificate,
  4151. ) (User, error) {
  4152. var user User
  4153. u, mergedUser, err := getUserForHook(username, nil)
  4154. if err != nil {
  4155. return user, err
  4156. }
  4157. if mergedUser.skipExternalAuth() {
  4158. return u, nil
  4159. }
  4160. pkey, err := util.GetSSHPublicKeyAsString(pubKey)
  4161. if err != nil {
  4162. return user, err
  4163. }
  4164. startTime := time.Now()
  4165. out, err := getExternalAuthResponse(username, password, pkey, keyboardInteractive, ip, protocol, tlsCert, u)
  4166. if err != nil {
  4167. return user, fmt.Errorf("external auth error for user %q, elapsed: %s: %w", username, time.Since(startTime), err)
  4168. }
  4169. providerLog(logger.LevelDebug, "external auth completed for user %q, elapsed: %s", username, time.Since(startTime))
  4170. if util.IsByteArrayEmpty(out) {
  4171. providerLog(logger.LevelDebug, "empty response from external hook, no modification requested for user %q, id: %d",
  4172. username, u.ID)
  4173. if u.ID == 0 {
  4174. return u, util.NewRecordNotFoundError(fmt.Sprintf("username %q does not exist", username))
  4175. }
  4176. err = checkPasswordAfterEmptyExtAuthResponse(&u, password, protocol)
  4177. return u, err
  4178. }
  4179. err = json.Unmarshal(out, &user)
  4180. if err != nil {
  4181. return user, fmt.Errorf("invalid external auth response: %v", err)
  4182. }
  4183. // an empty username means authentication failure
  4184. if user.Username == "" {
  4185. return user, ErrInvalidCredentials
  4186. }
  4187. updateUserFromExtAuthResponse(&user, password, pkey)
  4188. // some users want to map multiple login usernames with a single SFTPGo account
  4189. // for example an SFTP user logins using "user1" or "user2" and the external auth
  4190. // returns "user" in both cases, so we use the username returned from
  4191. // external auth and not the one used to login
  4192. if user.Username != username {
  4193. u, err = provider.userExists(user.Username, "")
  4194. }
  4195. if u.ID > 0 && err == nil {
  4196. user.ID = u.ID
  4197. user.UsedQuotaSize = u.UsedQuotaSize
  4198. user.UsedQuotaFiles = u.UsedQuotaFiles
  4199. user.UsedUploadDataTransfer = u.UsedUploadDataTransfer
  4200. user.UsedDownloadDataTransfer = u.UsedDownloadDataTransfer
  4201. user.LastQuotaUpdate = u.LastQuotaUpdate
  4202. user.LastLogin = u.LastLogin
  4203. user.LastPasswordChange = u.LastPasswordChange
  4204. user.FirstDownload = u.FirstDownload
  4205. user.FirstUpload = u.FirstUpload
  4206. user.CreatedAt = u.CreatedAt
  4207. user.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
  4208. // preserve TOTP config and recovery codes
  4209. user.Filters.TOTPConfig = u.Filters.TOTPConfig
  4210. user.Filters.RecoveryCodes = u.Filters.RecoveryCodes
  4211. user, err = updateUserAfterExternalAuth(&user)
  4212. if err == nil {
  4213. if protocol != protocolWebDAV {
  4214. webDAVUsersCache.swap(&user, password)
  4215. }
  4216. cachedUserPasswords.Add(user.Username, password, user.Password)
  4217. executeAction(operationUpdate, ActionExecutorSelf, "", actionObjectUser, user.Username, "", &user)
  4218. }
  4219. return user, err
  4220. }
  4221. err = provider.addUser(&user)
  4222. if err != nil {
  4223. return user, err
  4224. }
  4225. executeAction(operationAdd, ActionExecutorSelf, "", actionObjectUser, user.Username, "", &user)
  4226. return provider.userExists(user.Username, "")
  4227. }
  4228. func doPluginAuth(username, password string, pubKey []byte, ip, protocol string,
  4229. tlsCert *x509.Certificate, authScope int,
  4230. ) (User, error) {
  4231. var user User
  4232. u, mergedUser, userAsJSON, err := getUserAndJSONForHook(username, nil)
  4233. if err != nil {
  4234. return user, err
  4235. }
  4236. if mergedUser.skipExternalAuth() {
  4237. return u, nil
  4238. }
  4239. pkey, err := util.GetSSHPublicKeyAsString(pubKey)
  4240. if err != nil {
  4241. return user, err
  4242. }
  4243. startTime := time.Now()
  4244. out, err := plugin.Handler.Authenticate(username, password, ip, protocol, pkey, tlsCert, authScope, userAsJSON)
  4245. if err != nil {
  4246. return user, fmt.Errorf("plugin auth error for user %q: %v, elapsed: %v, auth scope: %d",
  4247. username, err, time.Since(startTime), authScope)
  4248. }
  4249. providerLog(logger.LevelDebug, "plugin auth completed for user %q, elapsed: %v, auth scope: %d",
  4250. username, time.Since(startTime), authScope)
  4251. if util.IsByteArrayEmpty(out) {
  4252. providerLog(logger.LevelDebug, "empty response from plugin auth, no modification requested for user %q id: %d, auth scope: %d",
  4253. username, u.ID, authScope)
  4254. if u.ID == 0 {
  4255. return u, util.NewRecordNotFoundError(fmt.Sprintf("username %q does not exist", username))
  4256. }
  4257. err = checkPasswordAfterEmptyExtAuthResponse(&u, password, protocol)
  4258. return u, err
  4259. }
  4260. err = json.Unmarshal(out, &user)
  4261. if err != nil {
  4262. return user, fmt.Errorf("invalid plugin auth response: %v", err)
  4263. }
  4264. updateUserFromExtAuthResponse(&user, password, pkey)
  4265. if u.ID > 0 {
  4266. user.ID = u.ID
  4267. user.UsedQuotaSize = u.UsedQuotaSize
  4268. user.UsedQuotaFiles = u.UsedQuotaFiles
  4269. user.UsedUploadDataTransfer = u.UsedUploadDataTransfer
  4270. user.UsedDownloadDataTransfer = u.UsedDownloadDataTransfer
  4271. user.LastQuotaUpdate = u.LastQuotaUpdate
  4272. user.LastLogin = u.LastLogin
  4273. user.LastPasswordChange = u.LastPasswordChange
  4274. user.FirstDownload = u.FirstDownload
  4275. user.FirstUpload = u.FirstUpload
  4276. // preserve TOTP config and recovery codes
  4277. user.Filters.TOTPConfig = u.Filters.TOTPConfig
  4278. user.Filters.RecoveryCodes = u.Filters.RecoveryCodes
  4279. user, err = updateUserAfterExternalAuth(&user)
  4280. if err == nil {
  4281. if protocol != protocolWebDAV {
  4282. webDAVUsersCache.swap(&user, password)
  4283. }
  4284. cachedUserPasswords.Add(user.Username, password, user.Password)
  4285. executeAction(operationUpdate, ActionExecutorSelf, "", actionObjectUser, user.Username, "", &user)
  4286. }
  4287. return user, err
  4288. }
  4289. err = provider.addUser(&user)
  4290. if err != nil {
  4291. return user, err
  4292. }
  4293. executeAction(operationAdd, ActionExecutorSelf, "", actionObjectUser, user.Username, "", &user)
  4294. return provider.userExists(user.Username, "")
  4295. }
  4296. func updateUserAfterExternalAuth(user *User) (User, error) {
  4297. if err := provider.updateUser(user); err != nil {
  4298. return *user, err
  4299. }
  4300. return provider.userExists(user.Username, "")
  4301. }
  4302. func getUserForHook(username string, oidcTokenFields *map[string]any) (User, User, error) {
  4303. u, err := provider.userExists(username, "")
  4304. if err != nil {
  4305. if !errors.Is(err, util.ErrNotFound) {
  4306. return u, u, err
  4307. }
  4308. u = User{
  4309. BaseUser: sdk.BaseUser{
  4310. ID: 0,
  4311. Username: username,
  4312. },
  4313. }
  4314. }
  4315. mergedUser := u.getACopy()
  4316. err = mergedUser.LoadAndApplyGroupSettings()
  4317. if err != nil {
  4318. return u, mergedUser, err
  4319. }
  4320. u.OIDCCustomFields = oidcTokenFields
  4321. return u, mergedUser, err
  4322. }
  4323. func getUserAndJSONForHook(username string, oidcTokenFields *map[string]any) (User, User, []byte, error) {
  4324. u, mergedUser, err := getUserForHook(username, oidcTokenFields)
  4325. if err != nil {
  4326. return u, mergedUser, nil, err
  4327. }
  4328. userAsJSON, err := json.Marshal(u)
  4329. if err != nil {
  4330. return u, mergedUser, userAsJSON, err
  4331. }
  4332. return u, mergedUser, userAsJSON, err
  4333. }
  4334. func isLastActivityRecent(lastActivity int64, minDelay time.Duration) bool {
  4335. lastActivityTime := util.GetTimeFromMsecSinceEpoch(lastActivity)
  4336. diff := -time.Until(lastActivityTime)
  4337. if diff < -10*time.Second {
  4338. return false
  4339. }
  4340. return diff < minDelay
  4341. }
  4342. func isExternalAuthConfigured(loginMethod string) bool {
  4343. if config.ExternalAuthHook != "" {
  4344. if config.ExternalAuthScope == 0 {
  4345. return true
  4346. }
  4347. switch loginMethod {
  4348. case LoginMethodPassword:
  4349. return config.ExternalAuthScope&1 != 0
  4350. case LoginMethodTLSCertificate:
  4351. return config.ExternalAuthScope&8 != 0
  4352. case LoginMethodTLSCertificateAndPwd:
  4353. return config.ExternalAuthScope&1 != 0 || config.ExternalAuthScope&8 != 0
  4354. }
  4355. }
  4356. switch loginMethod {
  4357. case LoginMethodPassword:
  4358. return plugin.Handler.HasAuthScope(plugin.AuthScopePassword)
  4359. case LoginMethodTLSCertificate:
  4360. return plugin.Handler.HasAuthScope(plugin.AuthScopeTLSCertificate)
  4361. case LoginMethodTLSCertificateAndPwd:
  4362. return plugin.Handler.HasAuthScope(plugin.AuthScopePassword) ||
  4363. plugin.Handler.HasAuthScope(plugin.AuthScopeTLSCertificate)
  4364. default:
  4365. return false
  4366. }
  4367. }
  4368. func getConfigPath(name, configDir string) string {
  4369. if !util.IsFileInputValid(name) {
  4370. return ""
  4371. }
  4372. if name != "" && !filepath.IsAbs(name) {
  4373. return filepath.Join(configDir, name)
  4374. }
  4375. return name
  4376. }
  4377. func checkReservedUsernames(username string) error {
  4378. if slices.Contains(reservedUsers, username) {
  4379. return util.NewValidationError("this username is reserved")
  4380. }
  4381. return nil
  4382. }
  4383. func errSchemaVersionTooOld(version int) error {
  4384. return fmt.Errorf("database schema version %d is too old, please see the upgrading docs: https://docs.sftpgo.com/latest/data-provider/#upgrading", version)
  4385. }
  4386. func providerLog(level logger.LogLevel, format string, v ...any) {
  4387. logger.Log(level, logSender, "", format, v...)
  4388. }