hosts.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package config
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "net"
  6. "strconv"
  7. "strings"
  8. "github.com/jcmturner/dnsutils/v2"
  9. )
  10. // GetKDCs returns the count of KDCs available and a map of KDC host names keyed on preference order.
  11. func (c *Config) GetKDCs(realm string, tcp bool) (int, map[int]string, error) {
  12. if realm == "" {
  13. realm = c.LibDefaults.DefaultRealm
  14. }
  15. kdcs := make(map[int]string)
  16. var count int
  17. // Get the KDCs from the krb5.conf.
  18. var ks []string
  19. for _, r := range c.Realms {
  20. if r.Realm != realm {
  21. continue
  22. }
  23. ks = r.KDC
  24. }
  25. count = len(ks)
  26. if count > 0 {
  27. // Order the kdcs randomly for preference.
  28. kdcs = randServOrder(ks)
  29. return count, kdcs, nil
  30. }
  31. if !c.LibDefaults.DNSLookupKDC {
  32. return count, kdcs, fmt.Errorf("no KDCs defined in configuration for realm %s", realm)
  33. }
  34. // Use DNS to resolve kerberos SRV records.
  35. proto := "udp"
  36. if tcp {
  37. proto = "tcp"
  38. }
  39. index, addrs, err := dnsutils.OrderedSRV("kerberos", proto, realm)
  40. if err != nil {
  41. return count, kdcs, err
  42. }
  43. if len(addrs) < 1 {
  44. return count, kdcs, fmt.Errorf("no KDC SRV records found for realm %s", realm)
  45. }
  46. count = index
  47. for k, v := range addrs {
  48. kdcs[k] = strings.TrimRight(v.Target, ".") + ":" + strconv.Itoa(int(v.Port))
  49. }
  50. return count, kdcs, nil
  51. }
  52. // GetKpasswdServers returns the count of kpasswd servers available and a map of kpasswd host names keyed on preference order.
  53. // https://web.mit.edu/kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html#realms - see kpasswd_server section
  54. func (c *Config) GetKpasswdServers(realm string, tcp bool) (int, map[int]string, error) {
  55. kdcs := make(map[int]string)
  56. var count int
  57. // Use DNS to resolve kerberos SRV records if configured to do so in krb5.conf.
  58. if c.LibDefaults.DNSLookupKDC {
  59. proto := "udp"
  60. if tcp {
  61. proto = "tcp"
  62. }
  63. c, addrs, err := dnsutils.OrderedSRV("kpasswd", proto, realm)
  64. if err != nil {
  65. return count, kdcs, err
  66. }
  67. if c < 1 {
  68. c, addrs, err = dnsutils.OrderedSRV("kerberos-adm", proto, realm)
  69. if err != nil {
  70. return count, kdcs, err
  71. }
  72. }
  73. if len(addrs) < 1 {
  74. return count, kdcs, fmt.Errorf("no kpasswd or kadmin SRV records found for realm %s", realm)
  75. }
  76. count = c
  77. for k, v := range addrs {
  78. kdcs[k] = strings.TrimRight(v.Target, ".") + ":" + strconv.Itoa(int(v.Port))
  79. }
  80. } else {
  81. // Get the KDCs from the krb5.conf an order them randomly for preference.
  82. var ks []string
  83. var ka []string
  84. for _, r := range c.Realms {
  85. if r.Realm == realm {
  86. ks = r.KPasswdServer
  87. ka = r.AdminServer
  88. break
  89. }
  90. }
  91. if len(ks) < 1 {
  92. for _, k := range ka {
  93. h, _, err := net.SplitHostPort(k)
  94. if err != nil {
  95. continue
  96. }
  97. ks = append(ks, h+":464")
  98. }
  99. }
  100. count = len(ks)
  101. if count < 1 {
  102. return count, kdcs, fmt.Errorf("no kpasswd or kadmin defined in configuration for realm %s", realm)
  103. }
  104. kdcs = randServOrder(ks)
  105. }
  106. return count, kdcs, nil
  107. }
  108. func randServOrder(ks []string) map[int]string {
  109. kdcs := make(map[int]string)
  110. count := len(ks)
  111. i := 1
  112. if count > 1 {
  113. l := len(ks)
  114. for l > 0 {
  115. ri := rand.Intn(l)
  116. kdcs[i] = ks[ri]
  117. if l > 1 {
  118. // Remove the entry from the source slice by swapping with the last entry and truncating
  119. ks[len(ks)-1], ks[ri] = ks[ri], ks[len(ks)-1]
  120. ks = ks[:len(ks)-1]
  121. l = len(ks)
  122. } else {
  123. l = 0
  124. }
  125. i++
  126. }
  127. } else {
  128. kdcs[i] = ks[0]
  129. }
  130. return kdcs
  131. }