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.

authorizedkeys.go 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package doctor
  4. import (
  5. "bufio"
  6. "bytes"
  7. "context"
  8. "fmt"
  9. "os"
  10. "path/filepath"
  11. "strings"
  12. asymkey_model "code.gitea.io/gitea/models/asymkey"
  13. "code.gitea.io/gitea/modules/container"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/setting"
  16. )
  17. const tplCommentPrefix = `# gitea public key`
  18. func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) error {
  19. if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
  20. return nil
  21. }
  22. fPath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
  23. f, err := os.Open(fPath)
  24. if err != nil {
  25. if !autofix {
  26. logger.Critical("Unable to open authorized_keys file. ERROR: %v", err)
  27. return fmt.Errorf("Unable to open authorized_keys file. ERROR: %w", err)
  28. }
  29. logger.Warn("Unable to open authorized_keys. (ERROR: %v). Attempting to rewrite...", err)
  30. if err = asymkey_model.RewriteAllPublicKeys(ctx); err != nil {
  31. logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
  32. return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err)
  33. }
  34. }
  35. defer f.Close()
  36. linesInAuthorizedKeys := make(container.Set[string])
  37. scanner := bufio.NewScanner(f)
  38. for scanner.Scan() {
  39. line := scanner.Text()
  40. if strings.HasPrefix(line, tplCommentPrefix) {
  41. continue
  42. }
  43. linesInAuthorizedKeys.Add(line)
  44. }
  45. f.Close()
  46. // now we regenerate and check if there are any lines missing
  47. regenerated := &bytes.Buffer{}
  48. if err := asymkey_model.RegeneratePublicKeys(ctx, regenerated); err != nil {
  49. logger.Critical("Unable to regenerate authorized_keys file. ERROR: %v", err)
  50. return fmt.Errorf("Unable to regenerate authorized_keys file. ERROR: %w", err)
  51. }
  52. scanner = bufio.NewScanner(regenerated)
  53. for scanner.Scan() {
  54. line := scanner.Text()
  55. if strings.HasPrefix(line, tplCommentPrefix) {
  56. continue
  57. }
  58. if linesInAuthorizedKeys.Contains(line) {
  59. continue
  60. }
  61. if !autofix {
  62. logger.Critical(
  63. "authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"",
  64. fPath,
  65. "gitea admin regenerate keys",
  66. "gitea doctor --run authorized-keys --fix")
  67. return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`)
  68. }
  69. logger.Warn("authorized_keys is out of date. Attempting rewrite...")
  70. err = asymkey_model.RewriteAllPublicKeys(ctx)
  71. if err != nil {
  72. logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
  73. return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err)
  74. }
  75. }
  76. return nil
  77. }
  78. func init() {
  79. Register(&Check{
  80. Title: "Check if OpenSSH authorized_keys file is up-to-date",
  81. Name: "authorized-keys",
  82. IsDefault: true,
  83. Run: checkAuthorizedKeys,
  84. Priority: 4,
  85. })
  86. }