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.

ssh_key_authorized_principals.go 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "bufio"
  7. "fmt"
  8. "io"
  9. "os"
  10. "path/filepath"
  11. "strings"
  12. "time"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/setting"
  15. "code.gitea.io/gitea/modules/util"
  16. )
  17. // _____ __ .__ .__ .___
  18. // / _ \ __ ___/ |_| |__ ___________|__|_______ ____ __| _/
  19. // / /_\ \| | \ __\ | \ / _ \_ __ \ \___ // __ \ / __ |
  20. // / | \ | /| | | Y ( <_> ) | \/ |/ /\ ___// /_/ |
  21. // \____|__ /____/ |__| |___| /\____/|__| |__/_____ \\___ >____ |
  22. // \/ \/ \/ \/ \/
  23. // __________ .__ .__ .__
  24. // \______ _______|__| ____ ____ |_____________ | | ______
  25. // | ___\_ __ | |/ \_/ ___\| \____ \__ \ | | / ___/
  26. // | | | | \| | | \ \___| | |_> / __ \| |__\___ \
  27. // |____| |__| |__|___| /\___ |__| __(____ |____/____ >
  28. // \/ \/ |__| \/ \/
  29. //
  30. // This file contains functions for creating authorized_principals files
  31. //
  32. // There is a dependence on the database within RewriteAllPrincipalKeys & RegeneratePrincipalKeys
  33. // The sshOpLocker is used from ssh_key_authorized_keys.go
  34. const authorizedPrincipalsFile = "authorized_principals"
  35. // RewriteAllPrincipalKeys removes any authorized principal and rewrite all keys from database again.
  36. // Note: x.Iterate does not get latest data after insert/delete, so we have to call this function
  37. // outside any session scope independently.
  38. func RewriteAllPrincipalKeys() error {
  39. return rewriteAllPrincipalKeys(x)
  40. }
  41. func rewriteAllPrincipalKeys(e Engine) error {
  42. // Don't rewrite key if internal server
  43. if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedPrincipalsFile {
  44. return nil
  45. }
  46. sshOpLocker.Lock()
  47. defer sshOpLocker.Unlock()
  48. if setting.SSH.RootPath != "" {
  49. // First of ensure that the RootPath is present, and if not make it with 0700 permissions
  50. // This of course doesn't guarantee that this is the right directory for authorized_keys
  51. // but at least if it's supposed to be this directory and it doesn't exist and we're the
  52. // right user it will at least be created properly.
  53. err := os.MkdirAll(setting.SSH.RootPath, 0o700)
  54. if err != nil {
  55. log.Error("Unable to MkdirAll(%s): %v", setting.SSH.RootPath, err)
  56. return err
  57. }
  58. }
  59. fPath := filepath.Join(setting.SSH.RootPath, authorizedPrincipalsFile)
  60. tmpPath := fPath + ".tmp"
  61. t, err := os.OpenFile(tmpPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600)
  62. if err != nil {
  63. return err
  64. }
  65. defer func() {
  66. t.Close()
  67. os.Remove(tmpPath)
  68. }()
  69. if setting.SSH.AuthorizedPrincipalsBackup {
  70. isExist, err := util.IsExist(fPath)
  71. if err != nil {
  72. log.Error("Unable to check if %s exists. Error: %v", fPath, err)
  73. return err
  74. }
  75. if isExist {
  76. bakPath := fmt.Sprintf("%s_%d.gitea_bak", fPath, time.Now().Unix())
  77. if err = util.CopyFile(fPath, bakPath); err != nil {
  78. return err
  79. }
  80. }
  81. }
  82. if err := regeneratePrincipalKeys(e, t); err != nil {
  83. return err
  84. }
  85. t.Close()
  86. return util.Rename(tmpPath, fPath)
  87. }
  88. // RegeneratePrincipalKeys regenerates the authorized_principals file
  89. func RegeneratePrincipalKeys(t io.StringWriter) error {
  90. return regeneratePrincipalKeys(x, t)
  91. }
  92. func regeneratePrincipalKeys(e Engine, t io.StringWriter) error {
  93. if err := e.Where("type = ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
  94. _, err = t.WriteString((bean.(*PublicKey)).AuthorizedString())
  95. return err
  96. }); err != nil {
  97. return err
  98. }
  99. fPath := filepath.Join(setting.SSH.RootPath, authorizedPrincipalsFile)
  100. isExist, err := util.IsExist(fPath)
  101. if err != nil {
  102. log.Error("Unable to check if %s exists. Error: %v", fPath, err)
  103. return err
  104. }
  105. if isExist {
  106. f, err := os.Open(fPath)
  107. if err != nil {
  108. return err
  109. }
  110. scanner := bufio.NewScanner(f)
  111. for scanner.Scan() {
  112. line := scanner.Text()
  113. if strings.HasPrefix(line, tplCommentPrefix) {
  114. scanner.Scan()
  115. continue
  116. }
  117. _, err = t.WriteString(line + "\n")
  118. if err != nil {
  119. f.Close()
  120. return err
  121. }
  122. }
  123. f.Close()
  124. }
  125. return nil
  126. }