dataprovider.go 142 KB

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