dataprovider.go 131 KB

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