Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

accounts.go 41KB

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