dataprovider.go 152 KB

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