You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

accounts.go 47KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "encoding/json"
  6. "fmt"
  7. "net/smtp"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "sync/atomic"
  12. "time"
  13. "unicode"
  14. "github.com/oragono/oragono/irc/caps"
  15. "github.com/oragono/oragono/irc/ldap"
  16. "github.com/oragono/oragono/irc/passwd"
  17. "github.com/oragono/oragono/irc/utils"
  18. "github.com/tidwall/buntdb"
  19. )
  20. const (
  21. keyAccountExists = "account.exists %s"
  22. keyAccountVerified = "account.verified %s"
  23. keyAccountCallback = "account.callback %s"
  24. keyAccountVerificationCode = "account.verificationcode %s"
  25. keyAccountName = "account.name %s" // stores the 'preferred name' of the account, not casemapped
  26. keyAccountRegTime = "account.registered.time %s"
  27. keyAccountCredentials = "account.credentials %s"
  28. keyAccountAdditionalNicks = "account.additionalnicks %s"
  29. keyAccountSettings = "account.settings %s"
  30. keyAccountVHost = "account.vhost %s"
  31. keyCertToAccount = "account.creds.certfp %s"
  32. keyAccountChannels = "account.channels %s"
  33. keyVHostQueueAcctToId = "vhostQueue %s"
  34. vhostRequestIdx = "vhostQueue"
  35. maxCertfpsPerAccount = 5
  36. )
  37. // everything about accounts is persistent; therefore, the database is the authoritative
  38. // source of truth for all account information. anything on the heap is just a cache
  39. type AccountManager struct {
  40. // XXX these are up here so they can be aligned to a 64-bit boundary, please forgive me
  41. // autoincrementing ID for vhost requests:
  42. vhostRequestID uint64
  43. vhostRequestPendingCount uint64
  44. sync.RWMutex // tier 2
  45. serialCacheUpdateMutex sync.Mutex // tier 3
  46. vHostUpdateMutex sync.Mutex // tier 3
  47. server *Server
  48. // track clients logged in to accounts
  49. accountToClients map[string][]*Client
  50. nickToAccount map[string]string
  51. skeletonToAccount map[string]string
  52. accountToMethod map[string]NickEnforcementMethod
  53. }
  54. func (am *AccountManager) Initialize(server *Server) {
  55. am.accountToClients = make(map[string][]*Client)
  56. am.nickToAccount = make(map[string]string)
  57. am.skeletonToAccount = make(map[string]string)
  58. am.accountToMethod = make(map[string]NickEnforcementMethod)
  59. am.server = server
  60. config := server.Config()
  61. am.buildNickToAccountIndex(config)
  62. am.initVHostRequestQueue(config)
  63. }
  64. func (am *AccountManager) buildNickToAccountIndex(config *Config) {
  65. if !config.Accounts.NickReservation.Enabled {
  66. return
  67. }
  68. nickToAccount := make(map[string]string)
  69. skeletonToAccount := make(map[string]string)
  70. accountToMethod := make(map[string]NickEnforcementMethod)
  71. existsPrefix := fmt.Sprintf(keyAccountExists, "")
  72. am.serialCacheUpdateMutex.Lock()
  73. defer am.serialCacheUpdateMutex.Unlock()
  74. err := am.server.store.View(func(tx *buntdb.Tx) error {
  75. err := tx.AscendGreaterOrEqual("", existsPrefix, func(key, value string) bool {
  76. if !strings.HasPrefix(key, existsPrefix) {
  77. return false
  78. }
  79. account := strings.TrimPrefix(key, existsPrefix)
  80. if _, err := tx.Get(fmt.Sprintf(keyAccountVerified, account)); err == nil {
  81. nickToAccount[account] = account
  82. accountName, err := tx.Get(fmt.Sprintf(keyAccountName, account))
  83. if err != nil {
  84. am.server.logger.Error("internal", "missing account name for", account)
  85. } else {
  86. skeleton, _ := Skeleton(accountName)
  87. skeletonToAccount[skeleton] = account
  88. }
  89. }
  90. if rawNicks, err := tx.Get(fmt.Sprintf(keyAccountAdditionalNicks, account)); err == nil {
  91. additionalNicks := unmarshalReservedNicks(rawNicks)
  92. for _, nick := range additionalNicks {
  93. cfnick, _ := CasefoldName(nick)
  94. nickToAccount[cfnick] = account
  95. skeleton, _ := Skeleton(nick)
  96. skeletonToAccount[skeleton] = account
  97. }
  98. }
  99. if rawPrefs, err := tx.Get(fmt.Sprintf(keyAccountSettings, account)); err == nil {
  100. var prefs AccountSettings
  101. err := json.Unmarshal([]byte(rawPrefs), &prefs)
  102. if err == nil && prefs.NickEnforcement != NickEnforcementOptional {
  103. accountToMethod[account] = prefs.NickEnforcement
  104. } else if err != nil {
  105. am.server.logger.Error("internal", "corrupt account creds", account)
  106. }
  107. }
  108. return true
  109. })
  110. return err
  111. })
  112. if err != nil {
  113. am.server.logger.Error("internal", "couldn't read reserved nicks", err.Error())
  114. } else {
  115. am.Lock()
  116. am.nickToAccount = nickToAccount
  117. am.skeletonToAccount = skeletonToAccount
  118. am.accountToMethod = accountToMethod
  119. am.Unlock()
  120. }
  121. }
  122. func (am *AccountManager) initVHostRequestQueue(config *Config) {
  123. if !config.Accounts.VHosts.Enabled {
  124. return
  125. }
  126. am.vHostUpdateMutex.Lock()
  127. defer am.vHostUpdateMutex.Unlock()
  128. // the db maps the account name to the autoincrementing integer ID of its request
  129. // create an numerically ordered index on ID, so we can list the oldest requests
  130. // finally, collect the integer id of the newest request and the total request count
  131. var total uint64
  132. var lastIDStr string
  133. err := am.server.store.Update(func(tx *buntdb.Tx) error {
  134. err := tx.CreateIndex(vhostRequestIdx, fmt.Sprintf(keyVHostQueueAcctToId, "*"), buntdb.IndexInt)
  135. if err != nil {
  136. return err
  137. }
  138. return tx.Descend(vhostRequestIdx, func(key, value string) bool {
  139. if lastIDStr == "" {
  140. lastIDStr = value
  141. }
  142. total++
  143. return true
  144. })
  145. })
  146. if err != nil {
  147. am.server.logger.Error("internal", "could not create vhost queue index", err.Error())
  148. }
  149. lastID, _ := strconv.ParseUint(lastIDStr, 10, 64)
  150. am.server.logger.Debug("services", fmt.Sprintf("vhost queue length is %d, autoincrementing id is %d", total, lastID))
  151. atomic.StoreUint64(&am.vhostRequestID, lastID)
  152. atomic.StoreUint64(&am.vhostRequestPendingCount, total)
  153. }
  154. func (am *AccountManager) NickToAccount(nick string) string {
  155. cfnick, err := CasefoldName(nick)
  156. if err != nil {
  157. return ""
  158. }
  159. am.RLock()
  160. defer am.RUnlock()
  161. return am.nickToAccount[cfnick]
  162. }
  163. // given an account, combine stored enforcement method with the config settings
  164. // to compute the actual enforcement method
  165. func configuredEnforcementMethod(config *Config, storedMethod NickEnforcementMethod) (result NickEnforcementMethod) {
  166. if !config.Accounts.NickReservation.Enabled {
  167. return NickEnforcementNone
  168. }
  169. result = storedMethod
  170. // if they don't have a custom setting, or customization is disabled, use the default
  171. if result == NickEnforcementOptional || !config.Accounts.NickReservation.AllowCustomEnforcement {
  172. result = config.Accounts.NickReservation.Method
  173. }
  174. if result == NickEnforcementOptional {
  175. // enforcement was explicitly enabled neither in the config or by the user
  176. result = NickEnforcementNone
  177. }
  178. return
  179. }
  180. // Given a nick, looks up the account that owns it and the method (none/timeout/strict)
  181. // used to enforce ownership.
  182. func (am *AccountManager) EnforcementStatus(cfnick, skeleton string) (account string, method NickEnforcementMethod) {
  183. config := am.server.Config()
  184. if !config.Accounts.NickReservation.Enabled {
  185. return "", NickEnforcementNone
  186. }
  187. am.RLock()
  188. defer am.RUnlock()
  189. finalEnforcementMethod := func(account_ string) (result NickEnforcementMethod) {
  190. storedMethod := am.accountToMethod[account_]
  191. return configuredEnforcementMethod(config, storedMethod)
  192. }
  193. nickAccount := am.nickToAccount[cfnick]
  194. skelAccount := am.skeletonToAccount[skeleton]
  195. if nickAccount == "" && skelAccount == "" {
  196. return "", NickEnforcementNone
  197. } else if nickAccount != "" && (skelAccount == nickAccount || skelAccount == "") {
  198. return nickAccount, finalEnforcementMethod(nickAccount)
  199. } else if skelAccount != "" && nickAccount == "" {
  200. return skelAccount, finalEnforcementMethod(skelAccount)
  201. } else {
  202. // nickAccount != skelAccount and both are nonempty:
  203. // two people have competing claims on (this casefolding of) this nick!
  204. nickMethod := finalEnforcementMethod(nickAccount)
  205. skelMethod := finalEnforcementMethod(skelAccount)
  206. switch {
  207. case skelMethod == NickEnforcementNone:
  208. return nickAccount, nickMethod
  209. case nickMethod == NickEnforcementNone:
  210. return skelAccount, skelMethod
  211. default:
  212. // nobody can use this nick
  213. return "!", NickEnforcementStrict
  214. }
  215. }
  216. }
  217. // Sets a custom enforcement method for an account and stores it in the database.
  218. func (am *AccountManager) SetEnforcementStatus(account string, method NickEnforcementMethod) (finalSettings AccountSettings, err error) {
  219. config := am.server.Config()
  220. if !(config.Accounts.NickReservation.Enabled && config.Accounts.NickReservation.AllowCustomEnforcement) {
  221. err = errFeatureDisabled
  222. return
  223. }
  224. setter := func(in AccountSettings) (out AccountSettings, err error) {
  225. out = in
  226. out.NickEnforcement = method
  227. return out, nil
  228. }
  229. _, err = am.ModifyAccountSettings(account, setter)
  230. if err != nil {
  231. return
  232. }
  233. // this update of the data plane is racey, but it's probably fine
  234. am.Lock()
  235. defer am.Unlock()
  236. if method == NickEnforcementOptional {
  237. delete(am.accountToMethod, account)
  238. } else {
  239. am.accountToMethod[account] = method
  240. }
  241. return
  242. }
  243. func (am *AccountManager) AccountToClients(account string) (result []*Client) {
  244. cfaccount, err := CasefoldName(account)
  245. if err != nil {
  246. return
  247. }
  248. am.RLock()
  249. defer am.RUnlock()
  250. return am.accountToClients[cfaccount]
  251. }
  252. func (am *AccountManager) Register(client *Client, account string, callbackNamespace string, callbackValue string, passphrase string, certfp string) error {
  253. casefoldedAccount, err := CasefoldName(account)
  254. skeleton, skerr := Skeleton(account)
  255. if err != nil || skerr != nil || account == "" || account == "*" {
  256. return errAccountCreation
  257. }
  258. if restrictedCasefoldedNicks[casefoldedAccount] || restrictedSkeletons[skeleton] {
  259. return errAccountAlreadyRegistered
  260. }
  261. config := am.server.AccountConfig()
  262. // final "is registration allowed" check, probably redundant:
  263. if !(config.Registration.Enabled || callbackNamespace == "admin") {
  264. return errFeatureDisabled
  265. }
  266. // if nick reservation is enabled, you can only register your current nickname
  267. // as an account; this prevents "land-grab" situations where someone else
  268. // registers your nick out from under you and then NS GHOSTs you
  269. // n.b. client is nil during a SAREGISTER:
  270. if config.NickReservation.Enabled && client != nil && client.NickCasefolded() != casefoldedAccount {
  271. return errAccountMustHoldNick
  272. }
  273. // can't register a guest nickname
  274. renamePrefix := strings.ToLower(config.NickReservation.RenamePrefix)
  275. if renamePrefix != "" && strings.HasPrefix(casefoldedAccount, renamePrefix) {
  276. return errAccountAlreadyRegistered
  277. }
  278. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  279. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  280. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  281. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  282. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  283. verificationCodeKey := fmt.Sprintf(keyAccountVerificationCode, casefoldedAccount)
  284. certFPKey := fmt.Sprintf(keyCertToAccount, certfp)
  285. var creds AccountCredentials
  286. creds.Version = 1
  287. err = creds.SetPassphrase(passphrase, am.server.Config().Accounts.Registration.BcryptCost)
  288. if err != nil {
  289. return err
  290. }
  291. creds.AddCertfp(certfp)
  292. credStr, err := creds.Serialize()
  293. if err != nil {
  294. return err
  295. }
  296. registeredTimeStr := strconv.FormatInt(time.Now().Unix(), 10)
  297. callbackSpec := fmt.Sprintf("%s:%s", callbackNamespace, callbackValue)
  298. var setOptions *buntdb.SetOptions
  299. ttl := config.Registration.VerifyTimeout
  300. if ttl != 0 {
  301. setOptions = &buntdb.SetOptions{Expires: true, TTL: ttl}
  302. }
  303. err = func() error {
  304. am.serialCacheUpdateMutex.Lock()
  305. defer am.serialCacheUpdateMutex.Unlock()
  306. // can't register an account with the same name as a registered nick
  307. if am.NickToAccount(casefoldedAccount) != "" {
  308. return errAccountAlreadyRegistered
  309. }
  310. return am.server.store.Update(func(tx *buntdb.Tx) error {
  311. _, err := am.loadRawAccount(tx, casefoldedAccount)
  312. if err != errAccountDoesNotExist {
  313. return errAccountAlreadyRegistered
  314. }
  315. if certfp != "" {
  316. // make sure certfp doesn't already exist because that'd be silly
  317. _, err := tx.Get(certFPKey)
  318. if err != buntdb.ErrNotFound {
  319. return errCertfpAlreadyExists
  320. }
  321. }
  322. tx.Set(accountKey, "1", setOptions)
  323. tx.Set(accountNameKey, account, setOptions)
  324. tx.Set(registeredTimeKey, registeredTimeStr, setOptions)
  325. tx.Set(credentialsKey, credStr, setOptions)
  326. tx.Set(callbackKey, callbackSpec, setOptions)
  327. if certfp != "" {
  328. tx.Set(certFPKey, casefoldedAccount, setOptions)
  329. }
  330. return nil
  331. })
  332. }()
  333. if err != nil {
  334. return err
  335. }
  336. code, err := am.dispatchCallback(client, casefoldedAccount, callbackNamespace, callbackValue)
  337. if err != nil {
  338. am.Unregister(casefoldedAccount)
  339. return errCallbackFailed
  340. } else {
  341. return am.server.store.Update(func(tx *buntdb.Tx) error {
  342. _, _, err = tx.Set(verificationCodeKey, code, setOptions)
  343. return err
  344. })
  345. }
  346. }
  347. // validatePassphrase checks whether a passphrase is allowed by our rules
  348. func validatePassphrase(passphrase string) error {
  349. // sanity check the length
  350. if len(passphrase) == 0 || len(passphrase) > 600 {
  351. return errAccountBadPassphrase
  352. }
  353. // we use * as a placeholder in some places, if it's gotten this far then fail
  354. if passphrase == "*" {
  355. return errAccountBadPassphrase
  356. }
  357. // for now, just enforce that spaces are not allowed
  358. for _, r := range passphrase {
  359. if unicode.IsSpace(r) {
  360. return errAccountBadPassphrase
  361. }
  362. }
  363. return nil
  364. }
  365. // changes the password for an account
  366. func (am *AccountManager) setPassword(account string, password string, hasPrivs bool) (err error) {
  367. cfAccount, err := CasefoldName(account)
  368. if err != nil {
  369. return errAccountDoesNotExist
  370. }
  371. credKey := fmt.Sprintf(keyAccountCredentials, cfAccount)
  372. var credStr string
  373. am.server.store.View(func(tx *buntdb.Tx) error {
  374. // no need to check verification status here or below;
  375. // you either need to be auth'ed to the account or be an oper to do this
  376. credStr, err = tx.Get(credKey)
  377. return nil
  378. })
  379. if err != nil {
  380. return errAccountDoesNotExist
  381. }
  382. var creds AccountCredentials
  383. err = json.Unmarshal([]byte(credStr), &creds)
  384. if err != nil {
  385. return err
  386. }
  387. if !hasPrivs && creds.Empty() {
  388. return errCredsExternallyManaged
  389. }
  390. err = creds.SetPassphrase(password, am.server.Config().Accounts.Registration.BcryptCost)
  391. if err != nil {
  392. return err
  393. }
  394. if creds.Empty() && !hasPrivs {
  395. return errEmptyCredentials
  396. }
  397. newCredStr, err := creds.Serialize()
  398. if err != nil {
  399. return err
  400. }
  401. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  402. curCredStr, err := tx.Get(credKey)
  403. if credStr != curCredStr {
  404. return errCASFailed
  405. }
  406. _, _, err = tx.Set(credKey, newCredStr, nil)
  407. return err
  408. })
  409. return err
  410. }
  411. func (am *AccountManager) addRemoveCertfp(account, certfp string, add bool, hasPrivs bool) (err error) {
  412. certfp, err = utils.NormalizeCertfp(certfp)
  413. if err != nil {
  414. return err
  415. }
  416. cfAccount, err := CasefoldName(account)
  417. if err != nil {
  418. return errAccountDoesNotExist
  419. }
  420. credKey := fmt.Sprintf(keyAccountCredentials, cfAccount)
  421. var credStr string
  422. am.server.store.View(func(tx *buntdb.Tx) error {
  423. credStr, err = tx.Get(credKey)
  424. return nil
  425. })
  426. if err != nil {
  427. return errAccountDoesNotExist
  428. }
  429. var creds AccountCredentials
  430. err = json.Unmarshal([]byte(credStr), &creds)
  431. if err != nil {
  432. return err
  433. }
  434. if !hasPrivs && creds.Empty() {
  435. return errCredsExternallyManaged
  436. }
  437. if add {
  438. err = creds.AddCertfp(certfp)
  439. } else {
  440. err = creds.RemoveCertfp(certfp)
  441. }
  442. if err != nil {
  443. return err
  444. }
  445. if creds.Empty() && !hasPrivs {
  446. return errEmptyCredentials
  447. }
  448. newCredStr, err := creds.Serialize()
  449. if err != nil {
  450. return err
  451. }
  452. certfpKey := fmt.Sprintf(keyCertToAccount, certfp)
  453. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  454. curCredStr, err := tx.Get(credKey)
  455. if credStr != curCredStr {
  456. return errCASFailed
  457. }
  458. if add {
  459. _, err = tx.Get(certfpKey)
  460. if err != buntdb.ErrNotFound {
  461. return errCertfpAlreadyExists
  462. }
  463. tx.Set(certfpKey, cfAccount, nil)
  464. } else {
  465. tx.Delete(certfpKey)
  466. }
  467. _, _, err = tx.Set(credKey, newCredStr, nil)
  468. return err
  469. })
  470. return err
  471. }
  472. func (am *AccountManager) dispatchCallback(client *Client, casefoldedAccount string, callbackNamespace string, callbackValue string) (string, error) {
  473. if callbackNamespace == "*" || callbackNamespace == "none" || callbackNamespace == "admin" {
  474. return "", nil
  475. } else if callbackNamespace == "mailto" {
  476. return am.dispatchMailtoCallback(client, casefoldedAccount, callbackValue)
  477. } else {
  478. return "", fmt.Errorf("Callback not implemented: %s", callbackNamespace)
  479. }
  480. }
  481. func (am *AccountManager) dispatchMailtoCallback(client *Client, casefoldedAccount string, callbackValue string) (code string, err error) {
  482. config := am.server.AccountConfig().Registration.Callbacks.Mailto
  483. code = utils.GenerateSecretToken()
  484. subject := config.VerifyMessageSubject
  485. if subject == "" {
  486. subject = fmt.Sprintf(client.t("Verify your account on %s"), am.server.name)
  487. }
  488. messageStrings := []string{
  489. fmt.Sprintf("From: %s\r\n", config.Sender),
  490. fmt.Sprintf("To: %s\r\n", callbackValue),
  491. fmt.Sprintf("Subject: %s\r\n", subject),
  492. "\r\n", // end headers, begin message body
  493. fmt.Sprintf(client.t("Account: %s"), casefoldedAccount) + "\r\n",
  494. fmt.Sprintf(client.t("Verification code: %s"), code) + "\r\n",
  495. "\r\n",
  496. client.t("To verify your account, issue the following command:") + "\r\n",
  497. fmt.Sprintf("/MSG NickServ VERIFY %s %s", casefoldedAccount, code) + "\r\n",
  498. }
  499. var message []byte
  500. for i := 0; i < len(messageStrings); i++ {
  501. message = append(message, []byte(messageStrings[i])...)
  502. }
  503. addr := fmt.Sprintf("%s:%d", config.Server, config.Port)
  504. var auth smtp.Auth
  505. if config.Username != "" && config.Password != "" {
  506. auth = smtp.PlainAuth("", config.Username, config.Password, config.Server)
  507. }
  508. // TODO: this will never send the password in plaintext over a nonlocal link,
  509. // but it might send the email in plaintext, regardless of the value of
  510. // config.TLS.InsecureSkipVerify
  511. err = smtp.SendMail(addr, auth, config.Sender, []string{callbackValue}, message)
  512. if err != nil {
  513. am.server.logger.Error("internal", "Failed to dispatch e-mail", err.Error())
  514. }
  515. return
  516. }
  517. func (am *AccountManager) Verify(client *Client, account string, code string) error {
  518. casefoldedAccount, err := CasefoldName(account)
  519. if err != nil || account == "" || account == "*" {
  520. return errAccountVerificationFailed
  521. }
  522. verifiedKey := fmt.Sprintf(keyAccountVerified, casefoldedAccount)
  523. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  524. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  525. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  526. verificationCodeKey := fmt.Sprintf(keyAccountVerificationCode, casefoldedAccount)
  527. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  528. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  529. var raw rawClientAccount
  530. func() {
  531. am.serialCacheUpdateMutex.Lock()
  532. defer am.serialCacheUpdateMutex.Unlock()
  533. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  534. raw, err = am.loadRawAccount(tx, casefoldedAccount)
  535. if err == errAccountDoesNotExist {
  536. return errAccountDoesNotExist
  537. } else if err != nil {
  538. return errAccountVerificationFailed
  539. } else if raw.Verified {
  540. return errAccountAlreadyVerified
  541. }
  542. // actually verify the code
  543. // a stored code of "" means a none callback / no code required
  544. success := false
  545. storedCode, err := tx.Get(verificationCodeKey)
  546. if err == nil {
  547. // this is probably unnecessary
  548. if storedCode == "" || utils.SecretTokensMatch(storedCode, code) {
  549. success = true
  550. }
  551. }
  552. if !success {
  553. return errAccountVerificationInvalidCode
  554. }
  555. // verify the account
  556. tx.Set(verifiedKey, "1", nil)
  557. // don't need the code anymore
  558. tx.Delete(verificationCodeKey)
  559. // re-set all other keys, removing the TTL
  560. tx.Set(accountKey, "1", nil)
  561. tx.Set(accountNameKey, raw.Name, nil)
  562. tx.Set(registeredTimeKey, raw.RegisteredAt, nil)
  563. tx.Set(callbackKey, raw.Callback, nil)
  564. tx.Set(credentialsKey, raw.Credentials, nil)
  565. var creds AccountCredentials
  566. // XXX we shouldn't do (de)serialization inside the txn,
  567. // but this is like 2 usec on my system
  568. json.Unmarshal([]byte(raw.Credentials), &creds)
  569. for _, cert := range creds.Certfps {
  570. certFPKey := fmt.Sprintf(keyCertToAccount, cert)
  571. tx.Set(certFPKey, casefoldedAccount, nil)
  572. }
  573. return nil
  574. })
  575. if err == nil {
  576. skeleton, _ := Skeleton(raw.Name)
  577. am.Lock()
  578. am.nickToAccount[casefoldedAccount] = casefoldedAccount
  579. am.skeletonToAccount[skeleton] = casefoldedAccount
  580. am.Unlock()
  581. }
  582. }()
  583. if err != nil {
  584. return err
  585. }
  586. nick := "[server admin]"
  587. if client != nil {
  588. nick = client.Nick()
  589. }
  590. am.server.logger.Info("accounts", "client", nick, "registered account", casefoldedAccount)
  591. raw.Verified = true
  592. clientAccount, err := am.deserializeRawAccount(raw)
  593. if err != nil {
  594. return err
  595. }
  596. if client != nil {
  597. am.Login(client, clientAccount)
  598. }
  599. return nil
  600. }
  601. // register and verify an account, for internal use
  602. func (am *AccountManager) SARegister(account, passphrase string) (err error) {
  603. err = am.Register(nil, account, "admin", "", passphrase, "")
  604. if err == nil {
  605. err = am.Verify(nil, account, "")
  606. }
  607. return
  608. }
  609. func marshalReservedNicks(nicks []string) string {
  610. return strings.Join(nicks, ",")
  611. }
  612. func unmarshalReservedNicks(nicks string) (result []string) {
  613. if nicks == "" {
  614. return
  615. }
  616. return strings.Split(nicks, ",")
  617. }
  618. func (am *AccountManager) SetNickReserved(client *Client, nick string, saUnreserve bool, reserve bool) error {
  619. cfnick, err := CasefoldName(nick)
  620. skeleton, skerr := Skeleton(nick)
  621. // garbage nick, or garbage options, or disabled
  622. nrconfig := am.server.AccountConfig().NickReservation
  623. if err != nil || skerr != nil || cfnick == "" || (reserve && saUnreserve) || !nrconfig.Enabled {
  624. return errAccountNickReservationFailed
  625. }
  626. // the cache is in sync with the DB while we hold serialCacheUpdateMutex
  627. am.serialCacheUpdateMutex.Lock()
  628. defer am.serialCacheUpdateMutex.Unlock()
  629. // find the affected account, which is usually the client's:
  630. account := client.Account()
  631. if saUnreserve {
  632. // unless this is a sadrop:
  633. account = am.NickToAccount(cfnick)
  634. if account == "" {
  635. // nothing to do
  636. return nil
  637. }
  638. }
  639. if account == "" {
  640. return errAccountNotLoggedIn
  641. }
  642. am.Lock()
  643. accountForNick := am.nickToAccount[cfnick]
  644. var accountForSkeleton string
  645. if reserve {
  646. accountForSkeleton = am.skeletonToAccount[skeleton]
  647. }
  648. am.Unlock()
  649. if reserve && (accountForNick != "" || accountForSkeleton != "") {
  650. return errNicknameReserved
  651. } else if !reserve && !saUnreserve && accountForNick != account {
  652. return errNicknameReserved
  653. } else if !reserve && cfnick == account {
  654. return errAccountCantDropPrimaryNick
  655. }
  656. nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, account)
  657. unverifiedAccountKey := fmt.Sprintf(keyAccountExists, cfnick)
  658. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  659. if reserve {
  660. // unverified accounts don't show up in NickToAccount yet (which is intentional),
  661. // however you shouldn't be able to reserve a nick out from under them
  662. _, err := tx.Get(unverifiedAccountKey)
  663. if err == nil {
  664. return errNicknameReserved
  665. }
  666. }
  667. rawNicks, err := tx.Get(nicksKey)
  668. if err != nil && err != buntdb.ErrNotFound {
  669. return err
  670. }
  671. nicks := unmarshalReservedNicks(rawNicks)
  672. if reserve {
  673. if len(nicks) >= nrconfig.AdditionalNickLimit {
  674. return errAccountTooManyNicks
  675. }
  676. nicks = append(nicks, nick)
  677. } else {
  678. // compute (original reserved nicks) minus cfnick
  679. var newNicks []string
  680. for _, reservedNick := range nicks {
  681. cfreservednick, _ := CasefoldName(reservedNick)
  682. if cfreservednick != cfnick {
  683. newNicks = append(newNicks, reservedNick)
  684. } else {
  685. // found the original, unfolded version of the nick we're dropping;
  686. // recompute the true skeleton from it
  687. skeleton, _ = Skeleton(reservedNick)
  688. }
  689. }
  690. nicks = newNicks
  691. }
  692. marshaledNicks := marshalReservedNicks(nicks)
  693. _, _, err = tx.Set(nicksKey, string(marshaledNicks), nil)
  694. return err
  695. })
  696. if err == errAccountTooManyNicks || err == errNicknameReserved {
  697. return err
  698. } else if err != nil {
  699. return errAccountNickReservationFailed
  700. }
  701. // success
  702. am.Lock()
  703. defer am.Unlock()
  704. if reserve {
  705. am.nickToAccount[cfnick] = account
  706. am.skeletonToAccount[skeleton] = account
  707. } else {
  708. delete(am.nickToAccount, cfnick)
  709. delete(am.skeletonToAccount, skeleton)
  710. }
  711. return nil
  712. }
  713. func (am *AccountManager) checkPassphrase(accountName, passphrase string) (account ClientAccount, err error) {
  714. account, err = am.LoadAccount(accountName)
  715. if err != nil {
  716. return
  717. }
  718. if !account.Verified {
  719. err = errAccountUnverified
  720. return
  721. }
  722. switch account.Credentials.Version {
  723. case 0:
  724. err = handleLegacyPasswordV0(am.server, accountName, account.Credentials, passphrase)
  725. case 1:
  726. if passwd.CompareHashAndPassword(account.Credentials.PassphraseHash, []byte(passphrase)) != nil {
  727. err = errAccountInvalidCredentials
  728. }
  729. default:
  730. err = errAccountInvalidCredentials
  731. }
  732. return
  733. }
  734. func (am *AccountManager) AuthenticateByPassphrase(client *Client, accountName string, passphrase string) (err error) {
  735. var account ClientAccount
  736. defer func() {
  737. if err == nil {
  738. am.Login(client, account)
  739. }
  740. }()
  741. ldapConf := am.server.Config().Accounts.LDAP
  742. if ldapConf.Enabled {
  743. err = ldap.CheckLDAPPassphrase(ldapConf, accountName, passphrase, am.server.logger)
  744. if err == nil {
  745. account, err = am.LoadAccount(accountName)
  746. // autocreate if necessary:
  747. if err == errAccountDoesNotExist && ldapConf.Autocreate {
  748. err = am.SARegister(accountName, "")
  749. if err != nil {
  750. return
  751. }
  752. account, err = am.LoadAccount(accountName)
  753. }
  754. return
  755. }
  756. }
  757. account, err = am.checkPassphrase(accountName, passphrase)
  758. return err
  759. }
  760. func (am *AccountManager) LoadAccount(accountName string) (result ClientAccount, err error) {
  761. casefoldedAccount, err := CasefoldName(accountName)
  762. if err != nil {
  763. err = errAccountDoesNotExist
  764. return
  765. }
  766. var raw rawClientAccount
  767. am.server.store.View(func(tx *buntdb.Tx) error {
  768. raw, err = am.loadRawAccount(tx, casefoldedAccount)
  769. return nil
  770. })
  771. if err != nil {
  772. return
  773. }
  774. result, err = am.deserializeRawAccount(raw)
  775. result.NameCasefolded = casefoldedAccount
  776. return
  777. }
  778. func (am *AccountManager) deserializeRawAccount(raw rawClientAccount) (result ClientAccount, err error) {
  779. result.Name = raw.Name
  780. regTimeInt, _ := strconv.ParseInt(raw.RegisteredAt, 10, 64)
  781. result.RegisteredAt = time.Unix(regTimeInt, 0).UTC()
  782. e := json.Unmarshal([]byte(raw.Credentials), &result.Credentials)
  783. if e != nil {
  784. am.server.logger.Error("internal", "could not unmarshal credentials", e.Error())
  785. err = errAccountDoesNotExist
  786. return
  787. }
  788. result.AdditionalNicks = unmarshalReservedNicks(raw.AdditionalNicks)
  789. result.Verified = raw.Verified
  790. if raw.VHost != "" {
  791. e := json.Unmarshal([]byte(raw.VHost), &result.VHost)
  792. if e != nil {
  793. am.server.logger.Warning("internal", "could not unmarshal vhost for account", result.Name, e.Error())
  794. // pretend they have no vhost and move on
  795. }
  796. }
  797. if raw.Settings != "" {
  798. e := json.Unmarshal([]byte(raw.Settings), &result.Settings)
  799. if e != nil {
  800. am.server.logger.Warning("internal", "could not unmarshal settings for account", result.Name, e.Error())
  801. }
  802. }
  803. return
  804. }
  805. func (am *AccountManager) loadRawAccount(tx *buntdb.Tx, casefoldedAccount string) (result rawClientAccount, err error) {
  806. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  807. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  808. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  809. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  810. verifiedKey := fmt.Sprintf(keyAccountVerified, casefoldedAccount)
  811. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  812. nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, casefoldedAccount)
  813. vhostKey := fmt.Sprintf(keyAccountVHost, casefoldedAccount)
  814. settingsKey := fmt.Sprintf(keyAccountSettings, casefoldedAccount)
  815. _, e := tx.Get(accountKey)
  816. if e == buntdb.ErrNotFound {
  817. err = errAccountDoesNotExist
  818. return
  819. }
  820. result.Name, _ = tx.Get(accountNameKey)
  821. result.RegisteredAt, _ = tx.Get(registeredTimeKey)
  822. result.Credentials, _ = tx.Get(credentialsKey)
  823. result.Callback, _ = tx.Get(callbackKey)
  824. result.AdditionalNicks, _ = tx.Get(nicksKey)
  825. result.VHost, _ = tx.Get(vhostKey)
  826. result.Settings, _ = tx.Get(settingsKey)
  827. if _, e = tx.Get(verifiedKey); e == nil {
  828. result.Verified = true
  829. }
  830. return
  831. }
  832. func (am *AccountManager) Unregister(account string) error {
  833. config := am.server.Config()
  834. casefoldedAccount, err := CasefoldName(account)
  835. if err != nil {
  836. return errAccountDoesNotExist
  837. }
  838. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  839. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  840. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  841. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  842. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  843. verificationCodeKey := fmt.Sprintf(keyAccountVerificationCode, casefoldedAccount)
  844. verifiedKey := fmt.Sprintf(keyAccountVerified, casefoldedAccount)
  845. nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, casefoldedAccount)
  846. settingsKey := fmt.Sprintf(keyAccountSettings, casefoldedAccount)
  847. vhostKey := fmt.Sprintf(keyAccountVHost, casefoldedAccount)
  848. vhostQueueKey := fmt.Sprintf(keyVHostQueueAcctToId, casefoldedAccount)
  849. channelsKey := fmt.Sprintf(keyAccountChannels, casefoldedAccount)
  850. var clients []*Client
  851. var registeredChannels []string
  852. // on our way out, unregister all the account's channels and delete them from the db
  853. defer func() {
  854. for _, channelName := range registeredChannels {
  855. am.server.channels.SetUnregistered(channelName, casefoldedAccount)
  856. }
  857. }()
  858. var credText string
  859. var rawNicks string
  860. am.serialCacheUpdateMutex.Lock()
  861. defer am.serialCacheUpdateMutex.Unlock()
  862. var accountName string
  863. var channelsStr string
  864. am.server.store.Update(func(tx *buntdb.Tx) error {
  865. tx.Delete(accountKey)
  866. accountName, _ = tx.Get(accountNameKey)
  867. tx.Delete(accountNameKey)
  868. tx.Delete(verifiedKey)
  869. tx.Delete(registeredTimeKey)
  870. tx.Delete(callbackKey)
  871. tx.Delete(verificationCodeKey)
  872. tx.Delete(settingsKey)
  873. rawNicks, _ = tx.Get(nicksKey)
  874. tx.Delete(nicksKey)
  875. credText, err = tx.Get(credentialsKey)
  876. tx.Delete(credentialsKey)
  877. tx.Delete(vhostKey)
  878. channelsStr, _ = tx.Get(channelsKey)
  879. tx.Delete(channelsKey)
  880. _, err := tx.Delete(vhostQueueKey)
  881. am.decrementVHostQueueCount(casefoldedAccount, err)
  882. return nil
  883. })
  884. if err == nil {
  885. var creds AccountCredentials
  886. if err = json.Unmarshal([]byte(credText), &creds); err == nil {
  887. for _, cert := range creds.Certfps {
  888. certFPKey := fmt.Sprintf(keyCertToAccount, cert)
  889. am.server.store.Update(func(tx *buntdb.Tx) error {
  890. if account, err := tx.Get(certFPKey); err == nil && account == casefoldedAccount {
  891. tx.Delete(certFPKey)
  892. }
  893. return nil
  894. })
  895. }
  896. }
  897. }
  898. skeleton, _ := Skeleton(accountName)
  899. additionalNicks := unmarshalReservedNicks(rawNicks)
  900. registeredChannels = unmarshalRegisteredChannels(channelsStr)
  901. am.Lock()
  902. defer am.Unlock()
  903. clients = am.accountToClients[casefoldedAccount]
  904. delete(am.accountToClients, casefoldedAccount)
  905. delete(am.nickToAccount, casefoldedAccount)
  906. delete(am.skeletonToAccount, skeleton)
  907. for _, nick := range additionalNicks {
  908. delete(am.nickToAccount, nick)
  909. additionalSkel, _ := Skeleton(nick)
  910. delete(am.skeletonToAccount, additionalSkel)
  911. }
  912. for _, client := range clients {
  913. if config.Accounts.RequireSasl.Enabled {
  914. client.Quit(client.t("You are no longer authorized to be on this server"), nil)
  915. // destroy acquires a semaphore so we can't call it while holding a lock
  916. go client.destroy(nil)
  917. } else {
  918. am.logoutOfAccount(client)
  919. }
  920. }
  921. if err != nil {
  922. return errAccountDoesNotExist
  923. }
  924. return nil
  925. }
  926. func unmarshalRegisteredChannels(channelsStr string) (result []string) {
  927. if channelsStr != "" {
  928. result = strings.Split(channelsStr, ",")
  929. }
  930. return
  931. }
  932. func (am *AccountManager) ChannelsForAccount(account string) (channels []string) {
  933. cfaccount, err := CasefoldName(account)
  934. if err != nil {
  935. return
  936. }
  937. var channelStr string
  938. key := fmt.Sprintf(keyAccountChannels, cfaccount)
  939. am.server.store.View(func(tx *buntdb.Tx) error {
  940. channelStr, _ = tx.Get(key)
  941. return nil
  942. })
  943. return unmarshalRegisteredChannels(channelStr)
  944. }
  945. func (am *AccountManager) AuthenticateByCertFP(client *Client, authzid string) error {
  946. if client.certfp == "" {
  947. return errAccountInvalidCredentials
  948. }
  949. var account string
  950. certFPKey := fmt.Sprintf(keyCertToAccount, client.certfp)
  951. err := am.server.store.View(func(tx *buntdb.Tx) error {
  952. account, _ = tx.Get(certFPKey)
  953. if account == "" {
  954. return errAccountInvalidCredentials
  955. }
  956. return nil
  957. })
  958. if err != nil {
  959. return err
  960. }
  961. if authzid != "" && authzid != account {
  962. return errAuthzidAuthcidMismatch
  963. }
  964. // ok, we found an account corresponding to their certificate
  965. clientAccount, err := am.LoadAccount(account)
  966. if err != nil {
  967. return err
  968. } else if !clientAccount.Verified {
  969. return errAccountUnverified
  970. }
  971. am.Login(client, clientAccount)
  972. return nil
  973. }
  974. type settingsMunger func(input AccountSettings) (output AccountSettings, err error)
  975. func (am *AccountManager) ModifyAccountSettings(account string, munger settingsMunger) (newSettings AccountSettings, err error) {
  976. casefoldedAccount, err := CasefoldName(account)
  977. if err != nil {
  978. return newSettings, errAccountDoesNotExist
  979. }
  980. // TODO implement this in general via a compare-and-swap API
  981. accountData, err := am.LoadAccount(casefoldedAccount)
  982. if err != nil {
  983. return
  984. } else if !accountData.Verified {
  985. return newSettings, errAccountUnverified
  986. }
  987. newSettings, err = munger(accountData.Settings)
  988. if err != nil {
  989. return
  990. }
  991. text, err := json.Marshal(newSettings)
  992. if err != nil {
  993. return
  994. }
  995. key := fmt.Sprintf(keyAccountSettings, casefoldedAccount)
  996. serializedValue := string(text)
  997. err = am.server.store.Update(func(tx *buntdb.Tx) (err error) {
  998. _, _, err = tx.Set(key, serializedValue, nil)
  999. return
  1000. })
  1001. if err != nil {
  1002. err = errAccountUpdateFailed
  1003. return
  1004. }
  1005. // success, push new settings into the client objects
  1006. am.Lock()
  1007. defer am.Unlock()
  1008. for _, client := range am.accountToClients[casefoldedAccount] {
  1009. client.SetAccountSettings(newSettings)
  1010. }
  1011. return
  1012. }
  1013. // represents someone's status in hostserv
  1014. type VHostInfo struct {
  1015. ApprovedVHost string
  1016. Enabled bool
  1017. Forbidden bool
  1018. RequestedVHost string
  1019. RejectedVHost string
  1020. RejectionReason string
  1021. LastRequestTime time.Time
  1022. }
  1023. // pair type, <VHostInfo, accountName>
  1024. type PendingVHostRequest struct {
  1025. VHostInfo
  1026. Account string
  1027. }
  1028. type vhostThrottleExceeded struct {
  1029. timeRemaining time.Duration
  1030. }
  1031. func (vhe *vhostThrottleExceeded) Error() string {
  1032. return fmt.Sprintf("Wait at least %v and try again", vhe.timeRemaining)
  1033. }
  1034. func (vh *VHostInfo) checkThrottle(cooldown time.Duration) (err error) {
  1035. if cooldown == 0 {
  1036. return nil
  1037. }
  1038. now := time.Now().UTC()
  1039. elapsed := now.Sub(vh.LastRequestTime)
  1040. if elapsed > cooldown {
  1041. // success
  1042. vh.LastRequestTime = now
  1043. return nil
  1044. } else {
  1045. return &vhostThrottleExceeded{timeRemaining: cooldown - elapsed}
  1046. }
  1047. }
  1048. // callback type implementing the actual business logic of vhost operations
  1049. type vhostMunger func(input VHostInfo) (output VHostInfo, err error)
  1050. func (am *AccountManager) VHostSet(account string, vhost string) (result VHostInfo, err error) {
  1051. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1052. output = input
  1053. output.Enabled = true
  1054. output.ApprovedVHost = vhost
  1055. return
  1056. }
  1057. return am.performVHostChange(account, munger)
  1058. }
  1059. func (am *AccountManager) VHostRequest(account string, vhost string, cooldown time.Duration) (result VHostInfo, err error) {
  1060. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1061. output = input
  1062. if input.Forbidden {
  1063. err = errVhostsForbidden
  1064. return
  1065. }
  1066. // you can update your existing request, but if you were approved or rejected,
  1067. // you can't spam a new request
  1068. if output.RequestedVHost == "" {
  1069. err = output.checkThrottle(cooldown)
  1070. }
  1071. if err != nil {
  1072. return
  1073. }
  1074. output.RequestedVHost = vhost
  1075. output.RejectedVHost = ""
  1076. output.RejectionReason = ""
  1077. output.LastRequestTime = time.Now().UTC()
  1078. return
  1079. }
  1080. return am.performVHostChange(account, munger)
  1081. }
  1082. func (am *AccountManager) VHostTake(account string, vhost string, cooldown time.Duration) (result VHostInfo, err error) {
  1083. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1084. output = input
  1085. if input.Forbidden {
  1086. err = errVhostsForbidden
  1087. return
  1088. }
  1089. // if you have a request pending, you can cancel it using take;
  1090. // otherwise, you're subject to the same throttling as if you were making a request
  1091. if output.RequestedVHost == "" {
  1092. err = output.checkThrottle(cooldown)
  1093. }
  1094. if err != nil {
  1095. return
  1096. }
  1097. output.ApprovedVHost = vhost
  1098. output.RequestedVHost = ""
  1099. output.RejectedVHost = ""
  1100. output.RejectionReason = ""
  1101. output.LastRequestTime = time.Now().UTC()
  1102. return
  1103. }
  1104. return am.performVHostChange(account, munger)
  1105. }
  1106. func (am *AccountManager) VHostApprove(account string) (result VHostInfo, err error) {
  1107. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1108. output = input
  1109. output.Enabled = true
  1110. output.ApprovedVHost = input.RequestedVHost
  1111. output.RequestedVHost = ""
  1112. output.RejectionReason = ""
  1113. return
  1114. }
  1115. return am.performVHostChange(account, munger)
  1116. }
  1117. func (am *AccountManager) VHostReject(account string, reason string) (result VHostInfo, err error) {
  1118. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1119. output = input
  1120. output.RejectedVHost = output.RequestedVHost
  1121. output.RequestedVHost = ""
  1122. output.RejectionReason = reason
  1123. return
  1124. }
  1125. return am.performVHostChange(account, munger)
  1126. }
  1127. func (am *AccountManager) VHostSetEnabled(client *Client, enabled bool) (result VHostInfo, err error) {
  1128. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1129. if input.ApprovedVHost == "" {
  1130. err = errNoVhost
  1131. return
  1132. }
  1133. output = input
  1134. output.Enabled = enabled
  1135. return
  1136. }
  1137. return am.performVHostChange(client.Account(), munger)
  1138. }
  1139. func (am *AccountManager) VHostForbid(account string, forbid bool) (result VHostInfo, err error) {
  1140. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1141. output = input
  1142. output.Forbidden = forbid
  1143. return
  1144. }
  1145. return am.performVHostChange(account, munger)
  1146. }
  1147. func (am *AccountManager) performVHostChange(account string, munger vhostMunger) (result VHostInfo, err error) {
  1148. account, err = CasefoldName(account)
  1149. if err != nil || account == "" {
  1150. err = errAccountDoesNotExist
  1151. return
  1152. }
  1153. am.vHostUpdateMutex.Lock()
  1154. defer am.vHostUpdateMutex.Unlock()
  1155. clientAccount, err := am.LoadAccount(account)
  1156. if err != nil {
  1157. err = errAccountDoesNotExist
  1158. return
  1159. } else if !clientAccount.Verified {
  1160. err = errAccountUnverified
  1161. return
  1162. }
  1163. result, err = munger(clientAccount.VHost)
  1164. if err != nil {
  1165. return
  1166. }
  1167. vhtext, err := json.Marshal(result)
  1168. if err != nil {
  1169. err = errAccountUpdateFailed
  1170. return
  1171. }
  1172. vhstr := string(vhtext)
  1173. key := fmt.Sprintf(keyAccountVHost, account)
  1174. queueKey := fmt.Sprintf(keyVHostQueueAcctToId, account)
  1175. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  1176. if _, _, err := tx.Set(key, vhstr, nil); err != nil {
  1177. return err
  1178. }
  1179. // update request queue
  1180. if clientAccount.VHost.RequestedVHost == "" && result.RequestedVHost != "" {
  1181. id := atomic.AddUint64(&am.vhostRequestID, 1)
  1182. if _, _, err = tx.Set(queueKey, strconv.FormatUint(id, 10), nil); err != nil {
  1183. return err
  1184. }
  1185. atomic.AddUint64(&am.vhostRequestPendingCount, 1)
  1186. } else if clientAccount.VHost.RequestedVHost != "" && result.RequestedVHost == "" {
  1187. _, err = tx.Delete(queueKey)
  1188. am.decrementVHostQueueCount(account, err)
  1189. }
  1190. return nil
  1191. })
  1192. if err != nil {
  1193. err = errAccountUpdateFailed
  1194. return
  1195. }
  1196. am.applyVhostToClients(account, result)
  1197. return result, nil
  1198. }
  1199. // XXX annoying helper method for keeping the queue count in sync with the DB
  1200. // `err` is the buntdb error returned from deleting the queue key
  1201. func (am *AccountManager) decrementVHostQueueCount(account string, err error) {
  1202. if err == nil {
  1203. // successfully deleted a queue entry, do a 2's complement decrement:
  1204. atomic.AddUint64(&am.vhostRequestPendingCount, ^uint64(0))
  1205. } else if err != buntdb.ErrNotFound {
  1206. am.server.logger.Error("internal", "buntdb dequeue error", account, err.Error())
  1207. }
  1208. }
  1209. func (am *AccountManager) VHostListRequests(limit int) (requests []PendingVHostRequest, total int) {
  1210. am.vHostUpdateMutex.Lock()
  1211. defer am.vHostUpdateMutex.Unlock()
  1212. total = int(atomic.LoadUint64(&am.vhostRequestPendingCount))
  1213. prefix := fmt.Sprintf(keyVHostQueueAcctToId, "")
  1214. accounts := make([]string, 0, limit)
  1215. err := am.server.store.View(func(tx *buntdb.Tx) error {
  1216. return tx.Ascend(vhostRequestIdx, func(key, value string) bool {
  1217. accounts = append(accounts, strings.TrimPrefix(key, prefix))
  1218. return len(accounts) < limit
  1219. })
  1220. })
  1221. if err != nil {
  1222. am.server.logger.Error("internal", "couldn't traverse vhost queue", err.Error())
  1223. return
  1224. }
  1225. for _, account := range accounts {
  1226. accountInfo, err := am.LoadAccount(account)
  1227. if err == nil {
  1228. requests = append(requests, PendingVHostRequest{
  1229. Account: account,
  1230. VHostInfo: accountInfo.VHost,
  1231. })
  1232. } else {
  1233. am.server.logger.Error("internal", "corrupt account", account, err.Error())
  1234. }
  1235. }
  1236. return
  1237. }
  1238. func (am *AccountManager) applyVHostInfo(client *Client, info VHostInfo) {
  1239. // if hostserv is disabled in config, then don't grant vhosts
  1240. // that were previously approved while it was enabled
  1241. if !am.server.AccountConfig().VHosts.Enabled {
  1242. return
  1243. }
  1244. vhost := ""
  1245. if info.Enabled && !info.Forbidden {
  1246. vhost = info.ApprovedVHost
  1247. }
  1248. oldNickmask := client.NickMaskString()
  1249. updated := client.SetVHost(vhost)
  1250. if updated {
  1251. // TODO: doing I/O here is kind of a kludge
  1252. go client.sendChghost(oldNickmask, client.Hostname())
  1253. }
  1254. }
  1255. func (am *AccountManager) applyVhostToClients(account string, result VHostInfo) {
  1256. am.RLock()
  1257. clients := am.accountToClients[account]
  1258. am.RUnlock()
  1259. for _, client := range clients {
  1260. am.applyVHostInfo(client, result)
  1261. }
  1262. }
  1263. func (am *AccountManager) Login(client *Client, account ClientAccount) {
  1264. changed := client.SetAccountName(account.Name)
  1265. if !changed {
  1266. return
  1267. }
  1268. client.nickTimer.Touch(nil)
  1269. am.applyVHostInfo(client, account.VHost)
  1270. casefoldedAccount := client.Account()
  1271. am.Lock()
  1272. defer am.Unlock()
  1273. am.accountToClients[casefoldedAccount] = append(am.accountToClients[casefoldedAccount], client)
  1274. for _, client := range am.accountToClients[casefoldedAccount] {
  1275. client.SetAccountSettings(account.Settings)
  1276. }
  1277. }
  1278. func (am *AccountManager) Logout(client *Client) {
  1279. am.Lock()
  1280. defer am.Unlock()
  1281. casefoldedAccount := client.Account()
  1282. if casefoldedAccount == "" {
  1283. return
  1284. }
  1285. am.logoutOfAccount(client)
  1286. clients := am.accountToClients[casefoldedAccount]
  1287. if len(clients) <= 1 {
  1288. delete(am.accountToClients, casefoldedAccount)
  1289. return
  1290. }
  1291. remainingClients := make([]*Client, len(clients)-1)
  1292. remainingPos := 0
  1293. for currentPos := 0; currentPos < len(clients); currentPos++ {
  1294. if clients[currentPos] != client {
  1295. remainingClients[remainingPos] = clients[currentPos]
  1296. remainingPos++
  1297. }
  1298. }
  1299. am.accountToClients[casefoldedAccount] = remainingClients
  1300. }
  1301. var (
  1302. // EnabledSaslMechanisms contains the SASL mechanisms that exist and that we support.
  1303. // This can be moved to some other data structure/place if we need to load/unload mechs later.
  1304. EnabledSaslMechanisms = map[string]func(*Server, *Client, string, []byte, *ResponseBuffer) bool{
  1305. "PLAIN": authPlainHandler,
  1306. "EXTERNAL": authExternalHandler,
  1307. }
  1308. )
  1309. // AccountCredentials stores the various methods for verifying accounts.
  1310. type AccountCredentials struct {
  1311. Version uint
  1312. PassphraseSalt []byte // legacy field, not used by v1 and later
  1313. PassphraseHash []byte
  1314. Certfps []string
  1315. }
  1316. func (ac *AccountCredentials) Empty() bool {
  1317. return len(ac.PassphraseHash) == 0 && len(ac.Certfps) == 0
  1318. }
  1319. // helper to assemble the serialized JSON for an account's credentials
  1320. func (ac *AccountCredentials) Serialize() (result string, err error) {
  1321. ac.Version = 1
  1322. credText, err := json.Marshal(*ac)
  1323. if err != nil {
  1324. return "", err
  1325. }
  1326. return string(credText), nil
  1327. }
  1328. func (ac *AccountCredentials) SetPassphrase(passphrase string, bcryptCost uint) (err error) {
  1329. if passphrase == "" {
  1330. ac.PassphraseHash = nil
  1331. return nil
  1332. }
  1333. if validatePassphrase(passphrase) != nil {
  1334. return errAccountBadPassphrase
  1335. }
  1336. ac.PassphraseHash, err = passwd.GenerateFromPassword([]byte(passphrase), int(bcryptCost))
  1337. if err != nil {
  1338. return errAccountBadPassphrase
  1339. }
  1340. return nil
  1341. }
  1342. func (ac *AccountCredentials) AddCertfp(certfp string) (err error) {
  1343. // XXX we require that certfp is already normalized (rather than normalize here
  1344. // and pass back the normalized version as an additional return parameter);
  1345. // this is just a final sanity check:
  1346. if len(certfp) != 64 {
  1347. return utils.ErrInvalidCertfp
  1348. }
  1349. for _, current := range ac.Certfps {
  1350. if certfp == current {
  1351. return errNoop
  1352. }
  1353. }
  1354. if maxCertfpsPerAccount <= len(ac.Certfps) {
  1355. return errLimitExceeded
  1356. }
  1357. ac.Certfps = append(ac.Certfps, certfp)
  1358. return nil
  1359. }
  1360. func (ac *AccountCredentials) RemoveCertfp(certfp string) (err error) {
  1361. found := false
  1362. newList := make([]string, 0, len(ac.Certfps))
  1363. for _, current := range ac.Certfps {
  1364. if current == certfp {
  1365. found = true
  1366. } else {
  1367. newList = append(newList, current)
  1368. }
  1369. }
  1370. if !found {
  1371. // this is important because it prevents you from deleting someone else's
  1372. // fingerprint record
  1373. return errNoop
  1374. }
  1375. ac.Certfps = newList
  1376. return nil
  1377. }
  1378. type BouncerAllowedSetting int
  1379. const (
  1380. BouncerAllowedServerDefault BouncerAllowedSetting = iota
  1381. BouncerDisallowedByUser
  1382. BouncerAllowedByUser
  1383. )
  1384. // controls whether/when clients without event-playback support see fake
  1385. // PRIVMSGs for JOINs
  1386. type ReplayJoinsSetting uint
  1387. const (
  1388. ReplayJoinsCommandsOnly = iota // replay in HISTORY or CHATHISTORY output
  1389. ReplayJoinsAlways // replay in HISTORY, CHATHISTORY, or autoreplay
  1390. ReplayJoinsNever // never replay
  1391. )
  1392. func replayJoinsSettingFromString(str string) (result ReplayJoinsSetting, err error) {
  1393. switch strings.ToLower(str) {
  1394. case "commands-only":
  1395. result = ReplayJoinsCommandsOnly
  1396. case "always":
  1397. result = ReplayJoinsAlways
  1398. case "never":
  1399. result = ReplayJoinsNever
  1400. default:
  1401. err = errInvalidParams
  1402. }
  1403. return
  1404. }
  1405. type AccountSettings struct {
  1406. AutoreplayLines *int
  1407. NickEnforcement NickEnforcementMethod
  1408. AllowBouncer BouncerAllowedSetting
  1409. ReplayJoins ReplayJoinsSetting
  1410. }
  1411. // ClientAccount represents a user account.
  1412. type ClientAccount struct {
  1413. // Name of the account.
  1414. Name string
  1415. NameCasefolded string
  1416. RegisteredAt time.Time
  1417. Credentials AccountCredentials
  1418. Verified bool
  1419. AdditionalNicks []string
  1420. VHost VHostInfo
  1421. Settings AccountSettings
  1422. }
  1423. // convenience for passing around raw serialized account data
  1424. type rawClientAccount struct {
  1425. Name string
  1426. RegisteredAt string
  1427. Credentials string
  1428. Callback string
  1429. Verified bool
  1430. AdditionalNicks string
  1431. VHost string
  1432. Settings string
  1433. }
  1434. // logoutOfAccount logs the client out of their current account.
  1435. func (am *AccountManager) logoutOfAccount(client *Client) {
  1436. if client.Account() == "" {
  1437. // already logged out
  1438. return
  1439. }
  1440. client.SetAccountName("")
  1441. go client.nickTimer.Touch(nil)
  1442. // dispatch account-notify
  1443. // TODO: doing the I/O here is kind of a kludge, let's move this somewhere else
  1444. go func() {
  1445. for friend := range client.Friends(caps.AccountNotify) {
  1446. friend.Send(nil, client.NickMaskString(), "ACCOUNT", "*")
  1447. }
  1448. }()
  1449. }