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.9KB

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