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  }