dataprovider.go 150 KB

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