123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- package config
- import (
- "fmt"
- "math/rand"
- "net"
- "strconv"
- "strings"
- "github.com/jcmturner/dnsutils/v2"
- )
- // GetKDCs returns the count of KDCs available and a map of KDC host names keyed on preference order.
- func (c *Config) GetKDCs(realm string, tcp bool) (int, map[int]string, error) {
- if realm == "" {
- realm = c.LibDefaults.DefaultRealm
- }
- kdcs := make(map[int]string)
- var count int
- // Get the KDCs from the krb5.conf.
- var ks []string
- for _, r := range c.Realms {
- if r.Realm != realm {
- continue
- }
- ks = r.KDC
- }
- count = len(ks)
- if count > 0 {
- // Order the kdcs randomly for preference.
- kdcs = randServOrder(ks)
- return count, kdcs, nil
- }
- if !c.LibDefaults.DNSLookupKDC {
- return count, kdcs, fmt.Errorf("no KDCs defined in configuration for realm %s", realm)
- }
- // Use DNS to resolve kerberos SRV records.
- proto := "udp"
- if tcp {
- proto = "tcp"
- }
- index, addrs, err := dnsutils.OrderedSRV("kerberos", proto, realm)
- if err != nil {
- return count, kdcs, err
- }
- if len(addrs) < 1 {
- return count, kdcs, fmt.Errorf("no KDC SRV records found for realm %s", realm)
- }
- count = index
- for k, v := range addrs {
- kdcs[k] = strings.TrimRight(v.Target, ".") + ":" + strconv.Itoa(int(v.Port))
- }
- return count, kdcs, nil
- }
- // GetKpasswdServers returns the count of kpasswd servers available and a map of kpasswd host names keyed on preference order.
- // https://web.mit.edu/kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html#realms - see kpasswd_server section
- func (c *Config) GetKpasswdServers(realm string, tcp bool) (int, map[int]string, error) {
- kdcs := make(map[int]string)
- var count int
- // Use DNS to resolve kerberos SRV records if configured to do so in krb5.conf.
- if c.LibDefaults.DNSLookupKDC {
- proto := "udp"
- if tcp {
- proto = "tcp"
- }
- c, addrs, err := dnsutils.OrderedSRV("kpasswd", proto, realm)
- if err != nil {
- return count, kdcs, err
- }
- if c < 1 {
- c, addrs, err = dnsutils.OrderedSRV("kerberos-adm", proto, realm)
- if err != nil {
- return count, kdcs, err
- }
- }
- if len(addrs) < 1 {
- return count, kdcs, fmt.Errorf("no kpasswd or kadmin SRV records found for realm %s", realm)
- }
- count = c
- for k, v := range addrs {
- kdcs[k] = strings.TrimRight(v.Target, ".") + ":" + strconv.Itoa(int(v.Port))
- }
- } else {
- // Get the KDCs from the krb5.conf an order them randomly for preference.
- var ks []string
- var ka []string
- for _, r := range c.Realms {
- if r.Realm == realm {
- ks = r.KPasswdServer
- ka = r.AdminServer
- break
- }
- }
- if len(ks) < 1 {
- for _, k := range ka {
- h, _, err := net.SplitHostPort(k)
- if err != nil {
- continue
- }
- ks = append(ks, h+":464")
- }
- }
- count = len(ks)
- if count < 1 {
- return count, kdcs, fmt.Errorf("no kpasswd or kadmin defined in configuration for realm %s", realm)
- }
- kdcs = randServOrder(ks)
- }
- return count, kdcs, nil
- }
- func randServOrder(ks []string) map[int]string {
- kdcs := make(map[int]string)
- count := len(ks)
- i := 1
- if count > 1 {
- l := len(ks)
- for l > 0 {
- ri := rand.Intn(l)
- kdcs[i] = ks[ri]
- if l > 1 {
- // Remove the entry from the source slice by swapping with the last entry and truncating
- ks[len(ks)-1], ks[ri] = ks[ri], ks[len(ks)-1]
- ks = ks[:len(ks)-1]
- l = len(ks)
- } else {
- l = 0
- }
- i++
- }
- } else {
- kdcs[i] = ks[0]
- }
- return kdcs
- }
|