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