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 44KB

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