|
|
@@ -1,123 +1,91 @@
|
|
|
package client
|
|
|
|
|
|
import (
|
|
|
+ "bytes"
|
|
|
+ "encoding/hex"
|
|
|
"fmt"
|
|
|
+ "github.com/jcmturner/asn1"
|
|
|
"github.com/jcmturner/gokrb5/config"
|
|
|
+ "github.com/jcmturner/gokrb5/crypto"
|
|
|
+ "github.com/jcmturner/gokrb5/iana/keyusage"
|
|
|
+ "github.com/jcmturner/gokrb5/keytab"
|
|
|
+ "github.com/jcmturner/gokrb5/messages"
|
|
|
+ "github.com/jcmturner/gokrb5/types"
|
|
|
"math/rand"
|
|
|
"net"
|
|
|
- "bytes"
|
|
|
+ "os"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
-func ASExchange() {
|
|
|
-
|
|
|
+type Client struct {
|
|
|
+ Username string
|
|
|
+ Password string
|
|
|
+ Keytab keytab.Keytab
|
|
|
+ Config *config.Config
|
|
|
}
|
|
|
|
|
|
-func SendToKDC(c *config.Config, b []byte) ([]byte, error) {
|
|
|
- var rb []byte
|
|
|
- var kdcs []string
|
|
|
- for _, r := range c.Realms {
|
|
|
- if r.Realm == c.LibDefaults.Default_realm {
|
|
|
- kdcs = r.Kdc
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
- if len(kdcs) < 1 {
|
|
|
- return rb, fmt.Errorf("No KDCs defined in configuration for realm %v", c.LibDefaults.Default_realm)
|
|
|
- }
|
|
|
- var kdc string
|
|
|
- if len(kdcs) > 1 {
|
|
|
- //Select one of the KDCs at random
|
|
|
- kdc = kdcs[rand.Intn(len(kdcs))]
|
|
|
- } else {
|
|
|
- kdc = kdcs[0]
|
|
|
+func NewClientWithPassword(username, password string) Client {
|
|
|
+ return Client{
|
|
|
+ Username: username,
|
|
|
+ Password: password,
|
|
|
+ Keytab: keytab.NewKeytab(),
|
|
|
+ Config: config.NewConfig(),
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- if c.LibDefaults.Udp_preference_limit == 1 {
|
|
|
- //1 means we should always use TCP
|
|
|
- rb, errtcp := sendTCP(kdc, b)
|
|
|
- if errtcp != nil {
|
|
|
- return rb, fmt.Errorf("Failed to communicate with KDC %v via TDP (%v)", kdc, errtcp)
|
|
|
- }
|
|
|
- if len(rb) < 1 {
|
|
|
- return rb, fmt.Errorf("No response data from KDC %v", kdc)
|
|
|
- }
|
|
|
- return rb, nil
|
|
|
+func NewClientWithKeytab(username string, kt keytab.Keytab) Client {
|
|
|
+ return Client{
|
|
|
+ Username: username,
|
|
|
+ Keytab: kt,
|
|
|
+ Config: config.NewConfig(),
|
|
|
}
|
|
|
- if len(b) <= c.LibDefaults.Udp_preference_limit {
|
|
|
- //Try UDP first, TCP second
|
|
|
- rb, errudp := sendUDP(kdc, b)
|
|
|
- if errudp != nil {
|
|
|
- rb, errtcp := sendTCP(kdc, b)
|
|
|
- if errtcp != nil {
|
|
|
- return rb, fmt.Errorf("Failed to communicate with KDC %v via UDP (%v) and then via TDP (%v)", kdc, errudp, errtcp)
|
|
|
- }
|
|
|
- }
|
|
|
- if len(rb) < 1 {
|
|
|
- return rb, fmt.Errorf("No response data from KDC %v", kdc)
|
|
|
- }
|
|
|
- return rb, nil
|
|
|
- }
|
|
|
- //Try TCP first, UDP second
|
|
|
- rb, errtcp := sendTCP(kdc, b)
|
|
|
- if errtcp != nil {
|
|
|
- rb, errudp := sendUDP(kdc, b)
|
|
|
- if errudp != nil {
|
|
|
- return rb, fmt.Errorf("Failed to communicate with KDC %v via TCP (%v) and then via UDP (%v)", kdc, errtcp, errudp)
|
|
|
- }
|
|
|
- }
|
|
|
- if len(rb) < 1 {
|
|
|
- return rb, fmt.Errorf("No response data from KDC %v", kdc)
|
|
|
- }
|
|
|
- return rb, nil
|
|
|
}
|
|
|
|
|
|
-func sendUDP(kdc string, b []byte) ([]byte, error) {
|
|
|
- var r []byte
|
|
|
- udpAddr, err := net.ResolveUDPAddr("udp", kdc)
|
|
|
- if err != nil {
|
|
|
- return r, fmt.Errorf("Error resolving KDC address: %v", err)
|
|
|
- }
|
|
|
- conn, err := net.DialUDP("udp", nil, udpAddr)
|
|
|
- if err != nil {
|
|
|
- return r, fmt.Errorf("Error establishing connection to KDC: %v", err)
|
|
|
- }
|
|
|
- defer conn.Close()
|
|
|
- conn.SetDeadline(time.Now().Add(time.Duration(5) * time.Second))
|
|
|
- _, err = conn.Write(b)
|
|
|
- if err != nil {
|
|
|
- return r, fmt.Errorf("Error sending to KDC: %v", err)
|
|
|
- }
|
|
|
- udpbuf := make([]byte, 4096)
|
|
|
- n, _, err := conn.ReadFrom(udpbuf)
|
|
|
- r = udpbuf[:n]
|
|
|
+func (cl *Client) WithPassword(p string) *Client {
|
|
|
+ cl.Password = p
|
|
|
+ return cl
|
|
|
+}
|
|
|
+
|
|
|
+func (cl *Client) WithKeytab(kt keytab.Keytab) *Client {
|
|
|
+ cl.Keytab = kt
|
|
|
+ return cl
|
|
|
+}
|
|
|
+
|
|
|
+func (cl *Client) WithConfig(cfg config.Config) *Client {
|
|
|
+ cl.Config = cfg
|
|
|
+ return cl
|
|
|
+}
|
|
|
+
|
|
|
+func (cl *Client) LoadConfig(cfgPath string) (*Client, error) {
|
|
|
+ cfg, err := config.Load(cfgPath)
|
|
|
if err != nil {
|
|
|
- return r, fmt.Errorf("Sending over UDP failed: %v", err)
|
|
|
+ return cl, err
|
|
|
}
|
|
|
- return r, nil
|
|
|
+ cl.Config = cfg
|
|
|
+ return cl, nil
|
|
|
}
|
|
|
|
|
|
-func sendTCP(kdc string, b []byte) ([]byte, error) {
|
|
|
- var r []byte
|
|
|
- tcpAddr, err := net.ResolveTCPAddr("tcp", kdc)
|
|
|
- if err != nil {
|
|
|
- return r, fmt.Errorf("Error resolving KDC address: %v", err)
|
|
|
+func (cl *Client) IsConfigured() bool {
|
|
|
+ if cl.Password == "" && len(cl.Keytab.Entries) < 1 {
|
|
|
+ return false
|
|
|
}
|
|
|
- conn, err := net.DialTCP("tcp", nil, tcpAddr)
|
|
|
- if err != nil {
|
|
|
- return r, fmt.Errorf("Error establishing connection to KDC: %v", err)
|
|
|
+ if cl.Username == "" {
|
|
|
+ return false
|
|
|
}
|
|
|
- defer conn.Close()
|
|
|
- conn.SetDeadline(time.Now().Add(time.Duration(5) * time.Second))
|
|
|
- _, err = conn.Write(b)
|
|
|
- if err != nil {
|
|
|
- return r, fmt.Errorf("Error sending to KDC: %v", err)
|
|
|
+ if cl.Config.LibDefaults.Default_realm == "" {
|
|
|
+ return false
|
|
|
}
|
|
|
- tcpbuf := bytes.NewBuffer(make([]byte, 4096))
|
|
|
- n, err := conn.ReadFrom(tcpbuf)
|
|
|
- r = tcpbuf.Bytes()[:n]
|
|
|
- if err != nil {
|
|
|
- return r, fmt.Errorf("Sending over TCP failed: %v", err)
|
|
|
+ for _, r := range cl.Config.Realms {
|
|
|
+ if r.Realm == cl.Config.LibDefaults.Default_realm {
|
|
|
+ if len(r.Kdc) > 0 {
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- return r, nil
|
|
|
+ return false
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+
|