Jonathan Turner 8 лет назад
Родитель
Сommit
ef17a551e8

+ 13 - 22
client/ASExchange.go

@@ -12,23 +12,15 @@ import (
 )
 )
 
 
 // ASExchange performs an AS exchange for the client to retrieve a TGT.
 // ASExchange performs an AS exchange for the client to retrieve a TGT.
-func (cl *Client) ASExchange(realm string, referral int) error {
+func (cl *Client) ASExchange(realm string, ASReq messages.ASReq, referral int) (messages.ASRep, error) {
 	if ok, err := cl.IsConfigured(); !ok {
 	if ok, err := cl.IsConfigured(); !ok {
-		return krberror.Errorf(err, krberror.ConfigError, "AS Exchange cannot be preformed")
-	}
-	ASReq, err := messages.NewASReq(realm, cl.Config, cl.Credentials.CName)
-	if err != nil {
-		return krberror.Errorf(err, krberror.KRBMsgError, "Error generating new AS_REQ")
-	}
-	err = setPAData(cl, messages.KRBError{}, &ASReq)
-	if err != nil {
-		return krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: failed setting AS_REQ PAData")
+		return messages.ASRep{}, krberror.Errorf(err, krberror.ConfigError, "AS Exchange cannot be preformed")
 	}
 	}
+
 	b, err := ASReq.Marshal()
 	b, err := ASReq.Marshal()
 	if err != nil {
 	if err != nil {
-		return krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed marshaling AS_REQ")
+		return messages.ASRep{}, krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed marshaling AS_REQ")
 	}
 	}
-
 	var ASRep messages.ASRep
 	var ASRep messages.ASRep
 
 
 	rb, err := cl.SendToKDC(b, realm)
 	rb, err := cl.SendToKDC(b, realm)
@@ -40,37 +32,36 @@ func (cl *Client) ASExchange(realm string, referral int) error {
 				cl.GoKrb5Conf.AssumePAEncTimestampRequired = true
 				cl.GoKrb5Conf.AssumePAEncTimestampRequired = true
 				err = setPAData(cl, e, &ASReq)
 				err = setPAData(cl, e, &ASReq)
 				if err != nil {
 				if err != nil {
-					return krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: failed setting AS_REQ PAData for pre-authentication required")
+					return messages.ASRep{}, krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: failed setting AS_REQ PAData for pre-authentication required")
 				}
 				}
 				b, err := ASReq.Marshal()
 				b, err := ASReq.Marshal()
 				if err != nil {
 				if err != nil {
-					return krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed marshaling AS_REQ with PAData")
+					return messages.ASRep{}, krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed marshaling AS_REQ with PAData")
 				}
 				}
 				rb, err = cl.SendToKDC(b, realm)
 				rb, err = cl.SendToKDC(b, realm)
 				if err != nil {
 				if err != nil {
-					return krberror.Errorf(err, krberror.NetworkingError, "AS Exchange Error: failed sending AS_REQ to KDC")
+					return messages.ASRep{}, krberror.Errorf(err, krberror.NetworkingError, "AS Exchange Error: failed sending AS_REQ to KDC")
 				}
 				}
 			case errorcode.KDC_ERR_WRONG_REALM:
 			case errorcode.KDC_ERR_WRONG_REALM:
 				// Client referral https://tools.ietf.org/html/rfc6806.html#section-7
 				// Client referral https://tools.ietf.org/html/rfc6806.html#section-7
 				if referral > 5 {
 				if referral > 5 {
-					return krberror.Errorf(err, krberror.KRBMsgError, "maximum number of client referrals exceeded")
+					return messages.ASRep{}, krberror.Errorf(err, krberror.KRBMsgError, "maximum number of client referrals exceeded")
 				}
 				}
 				referral++
 				referral++
-				return cl.ASExchange(e.CRealm, referral)
+				return cl.ASExchange(e.CRealm, ASReq, referral)
 			}
 			}
 		} else {
 		} else {
-			return krberror.Errorf(err, krberror.NetworkingError, "AS Exchange Error: failed sending AS_REQ to KDC")
+			return messages.ASRep{}, krberror.Errorf(err, krberror.NetworkingError, "AS Exchange Error: failed sending AS_REQ to KDC")
 		}
 		}
 	}
 	}
 	err = ASRep.Unmarshal(rb)
 	err = ASRep.Unmarshal(rb)
 	if err != nil {
 	if err != nil {
-		return krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed to process the AS_REP")
+		return messages.ASRep{}, krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed to process the AS_REP")
 	}
 	}
 	if ok, err := ASRep.IsValid(cl.Config, cl.Credentials, ASReq); !ok {
 	if ok, err := ASRep.IsValid(cl.Config, cl.Credentials, ASReq); !ok {
-		return krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: AS_REP is not valid")
+		return messages.ASRep{}, krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: AS_REP is not valid")
 	}
 	}
-	cl.AddSession(ASRep.Ticket, ASRep.DecryptedEncPart)
-	return nil
+	return ASRep, nil
 }
 }
 
 
 func setPAData(cl *Client, krberr messages.KRBError, ASReq *messages.ASReq) error {
 func setPAData(cl *Client, krberr messages.KRBError, ASReq *messages.ASReq) error {

+ 15 - 1
client/client.go

@@ -12,6 +12,7 @@ import (
 	"gopkg.in/jcmturner/gokrb5.v4/iana/errorcode"
 	"gopkg.in/jcmturner/gokrb5.v4/iana/errorcode"
 	"gopkg.in/jcmturner/gokrb5.v4/iana/nametype"
 	"gopkg.in/jcmturner/gokrb5.v4/iana/nametype"
 	"gopkg.in/jcmturner/gokrb5.v4/keytab"
 	"gopkg.in/jcmturner/gokrb5.v4/keytab"
+	"gopkg.in/jcmturner/gokrb5.v4/krberror"
 	"gopkg.in/jcmturner/gokrb5.v4/messages"
 	"gopkg.in/jcmturner/gokrb5.v4/messages"
 	"gopkg.in/jcmturner/gokrb5.v4/types"
 	"gopkg.in/jcmturner/gokrb5.v4/types"
 )
 )
@@ -197,5 +198,18 @@ func (cl *Client) Login() error {
 	if cl.Credentials.Realm == "" {
 	if cl.Credentials.Realm == "" {
 		cl.Credentials.Realm = cl.Config.LibDefaults.DefaultRealm
 		cl.Credentials.Realm = cl.Config.LibDefaults.DefaultRealm
 	}
 	}
-	return cl.ASExchange(cl.Credentials.Realm, 0)
+	ASReq, err := messages.NewASReqForTGT(cl.Credentials.Realm, cl.Config, cl.Credentials.CName)
+	if err != nil {
+		return krberror.Errorf(err, krberror.KRBMsgError, "error generating new AS_REQ")
+	}
+	err = setPAData(cl, messages.KRBError{}, &ASReq)
+	if err != nil {
+		return krberror.Errorf(err, krberror.KRBMsgError, "failed setting AS_REQ PAData")
+	}
+	ASRep, err := cl.ASExchange(cl.Credentials.Realm, ASReq, 0)
+	if err != nil {
+		return err
+	}
+	cl.AddSession(ASRep.Ticket, ASRep.DecryptedEncPart)
+	return nil
 }
 }

+ 3 - 6
client/client_integration_test.go

@@ -638,10 +638,6 @@ func TestClient_ChangePasswd(t *testing.T) {
 	cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
 	cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
 	cl.WithConfig(c)
 	cl.WithConfig(c)
 
 
-	err = cl.Login()
-	if err != nil {
-		t.Fatalf("error on login: %v", err)
-	}
 	ok, err := cl.ChangePasswd("newpassword")
 	ok, err := cl.ChangePasswd("newpassword")
 	if err != nil {
 	if err != nil {
 		t.Fatalf("error changing password: %v", err)
 		t.Fatalf("error changing password: %v", err)
@@ -650,8 +646,9 @@ func TestClient_ChangePasswd(t *testing.T) {
 
 
 	cl = NewClientWithPassword("testuser1", "TEST.GOKRB5", "newpassword")
 	cl = NewClientWithPassword("testuser1", "TEST.GOKRB5", "newpassword")
 	cl.WithConfig(c)
 	cl.WithConfig(c)
-	err = cl.Login()
+	ok, err = cl.ChangePasswd(testdata.TESTUSER1_PASSWORD)
 	if err != nil {
 	if err != nil {
-		t.Fatalf("error on login with new password: %v", err)
+		t.Fatalf("error changing password: %v", err)
 	}
 	}
+	assert.True(t, ok, "password was not changed back")
 }
 }

+ 5 - 5
client/passwd.go

@@ -5,11 +5,10 @@ import (
 	"net"
 	"net"
 
 
 	"gopkg.in/jcmturner/gokrb5.v4/kadmin"
 	"gopkg.in/jcmturner/gokrb5.v4/kadmin"
+	"gopkg.in/jcmturner/gokrb5.v4/messages"
 )
 )
 
 
 const (
 const (
-	passwdChangeSPN = "kadmin/changepw"
-
 	KRB5_KPASSWD_SUCCESS             = 0
 	KRB5_KPASSWD_SUCCESS             = 0
 	KRB5_KPASSWD_MALFORMED           = 1
 	KRB5_KPASSWD_MALFORMED           = 1
 	KRB5_KPASSWD_HARDERROR           = 2
 	KRB5_KPASSWD_HARDERROR           = 2
@@ -21,12 +20,13 @@ const (
 )
 )
 
 
 func (cl *Client) ChangePasswd(newPasswd string) (bool, error) {
 func (cl *Client) ChangePasswd(newPasswd string) (bool, error) {
-	tkt, skey, err := cl.GetServiceTicket(passwdChangeSPN)
+	ASReq, err := messages.NewASReqForChgPasswd(cl.Credentials.Realm, cl.Config, cl.Credentials.CName)
 	if err != nil {
 	if err != nil {
-		return false, fmt.Errorf("could not get service ticket: %v", err)
+		return false, err
 	}
 	}
+	ASRep, err := cl.ASExchange(cl.Credentials.Realm, ASReq, 0)
 
 
-	msg, key, err := kadmin.ChangePasswdMsg(cl.Credentials.CName, cl.Credentials.Realm, newPasswd, tkt, skey)
+	msg, key, err := kadmin.ChangePasswdMsg(cl.Credentials.CName, cl.Credentials.Realm, newPasswd, ASRep.Ticket, ASRep.DecryptedEncPart.Key)
 	r, err := cl.sendToKPasswd(msg)
 	r, err := cl.sendToKPasswd(msg)
 	err = r.Decrypt(key)
 	err = r.Decrypt(key)
 	if err != nil {
 	if err != nil {

+ 1 - 1
client/session.go

@@ -89,7 +89,7 @@ func (cl *Client) updateSession(s *session) error {
 			return err
 			return err
 		}
 		}
 	} else {
 	} else {
-		err := cl.ASExchange(s.Realm, 0)
+		err := cl.Login()
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 29 - 0
kadmin/changepasswddata_test.go

@@ -0,0 +1,29 @@
+package kadmin
+
+import (
+	"encoding/hex"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"gopkg.in/jcmturner/gokrb5.v4/iana/nametype"
+	"gopkg.in/jcmturner/gokrb5.v4/testdata"
+	"gopkg.in/jcmturner/gokrb5.v4/types"
+)
+
+func TestChangePasswdData_Marshal(t *testing.T) {
+	chgpasswd := ChangePasswdData{
+		NewPasswd: []byte("newpassword"),
+		TargName:  types.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, "testuser1"),
+		TargRealm: "TEST.GOKRB5",
+	}
+	chpwdb, err := chgpasswd.Marshal()
+	if err != nil {
+		t.Fatalf("error marshaling change passwd data: %v\n", err)
+	}
+	v := "ChangePasswdData"
+	b, err := hex.DecodeString(testdata.TestVectors[v])
+	if err != nil {
+		t.Fatalf("Test vector read error of %s: %v\n", v, err)
+	}
+	assert.Equal(t, b, chpwdb, "marshaled bytes of change passwd data not as expected")
+}

+ 20 - 19
kadmin/message.go

@@ -3,7 +3,6 @@ package kadmin
 import (
 import (
 	"bytes"
 	"bytes"
 	"encoding/binary"
 	"encoding/binary"
-	"encoding/hex"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"math"
 	"math"
@@ -13,7 +12,7 @@ import (
 )
 )
 
 
 const (
 const (
-	verisonHex = "0xff80"
+	verisonHex = "ff80"
 )
 )
 
 
 type Request struct {
 type Request struct {
@@ -22,17 +21,19 @@ type Request struct {
 }
 }
 
 
 type Reply struct {
 type Reply struct {
-	APREP      messages.APRep
-	KRBPriv    messages.KRBPriv
-	KRBError   messages.KRBError
-	IsKRBError bool
-	ResultCode uint16
-	Result     string
+	MessageLength int
+	Version       int
+	APREPLength   int
+	APREP         messages.APRep
+	KRBPriv       messages.KRBPriv
+	KRBError      messages.KRBError
+	IsKRBError    bool
+	ResultCode    uint16
+	Result        string
 }
 }
 
 
 func (m *Request) Marshal() (b []byte, err error) {
 func (m *Request) Marshal() (b []byte, err error) {
-	vb, _ := hex.DecodeString(verisonHex)
-	b = append(b, vb...)
+	b = []byte{255, 128} // protocol version number: contains the hex constant 0xff80 (big-endian integer).
 	ab, e := m.APREQ.Marshal()
 	ab, e := m.APREQ.Marshal()
 	if e != nil {
 	if e != nil {
 		err = fmt.Errorf("error marshaling AP_REQ: %v", e)
 		err = fmt.Errorf("error marshaling AP_REQ: %v", e)
@@ -63,24 +64,24 @@ func (m *Request) Marshal() (b []byte, err error) {
 }
 }
 
 
 func (m *Reply) Unmarshal(b []byte) error {
 func (m *Reply) Unmarshal(b []byte) error {
-	msgLen := int(binary.BigEndian.Uint16(b[0:2]))
-	v := int(binary.BigEndian.Uint16(b[2:4]))
-	if v != 1 {
-		return fmt.Errorf("kadmin reply has incorrect protocol version number: %d", v)
+	m.MessageLength = int(binary.BigEndian.Uint16(b[0:2]))
+	m.Version = int(binary.BigEndian.Uint16(b[2:4]))
+	if m.Version != 1 {
+		return fmt.Errorf("kadmin reply has incorrect protocol version number: %d", m.Version)
 	}
 	}
-	APRepLen := int(binary.BigEndian.Uint16(b[4:6]))
-	if APRepLen != 0 {
-		err := m.APREP.Unmarshal(b[6 : 6+APRepLen])
+	m.APREPLength = int(binary.BigEndian.Uint16(b[4:6]))
+	if m.APREPLength != 0 {
+		err := m.APREP.Unmarshal(b[6 : 6+m.APREPLength])
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		err = m.KRBPriv.Unmarshal(b[6+APRepLen : msgLen])
+		err = m.KRBPriv.Unmarshal(b[6+m.APREPLength : m.MessageLength])
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
 	} else {
 	} else {
 		m.IsKRBError = true
 		m.IsKRBError = true
-		m.KRBError.Unmarshal(b[6:msgLen])
+		m.KRBError.Unmarshal(b[6:m.MessageLength])
 		m.ResultCode, m.Result = parseResponse(m.KRBError.EData)
 		m.ResultCode, m.Result = parseResponse(m.KRBError.EData)
 	}
 	}
 	return nil
 	return nil

+ 35 - 0
kadmin/message_test.go

@@ -0,0 +1,35 @@
+package kadmin
+
+import (
+	"encoding/hex"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"gopkg.in/jcmturner/gokrb5.v4/iana"
+	"gopkg.in/jcmturner/gokrb5.v4/iana/msgtype"
+	"gopkg.in/jcmturner/gokrb5.v4/testdata"
+)
+
+func TestUnmarshalReply(t *testing.T) {
+	var a Reply
+	v := "Kpasswd_Rep"
+	b, err := hex.DecodeString(testdata.TestVectors[v])
+	if err != nil {
+		t.Fatalf("Test vector read error of %s: %v\n", v, err)
+	}
+	err = a.Unmarshal(b)
+	if err != nil {
+		t.Fatalf("Unmarshal error of %s: %v\n", v, err)
+	}
+	assert.Equal(t, 236, a.MessageLength, "message length not as expected")
+	assert.Equal(t, 1, a.Version, "message version not as expected")
+	assert.Equal(t, 140, a.APREPLength, "AP_REP length not as expected")
+	assert.Equal(t, iana.PVNO, a.APREP.PVNO, "AP_REP within reply not as expected")
+	assert.Equal(t, msgtype.KRB_AP_REP, a.APREP.MsgType, "AP_REP message type within reply not as expected")
+	assert.Equal(t, int32(18), a.APREP.EncPart.EType, "AP_REQ etype not as expected")
+	assert.Equal(t, iana.PVNO, a.KRBPriv.PVNO, "KRBPriv within reply not as expected")
+	assert.Equal(t, msgtype.KRB_PRIV, a.KRBPriv.MsgType, "KRBPriv type within reply not as expected")
+	assert.Equal(t, int32(18), a.KRBPriv.EncPart.EType, "KRBPriv etype not as expected")
+}
+
+// Request marshal is tested via integration test in the client package due to the dynamic keys and encryption.

+ 1 - 3
kadmin/passwd.go

@@ -31,7 +31,7 @@ func ChangePasswdMsg(cname types.PrincipalName, realm, password string, tkt mess
 		err = krberror.Errorf(err, krberror.KRBMsgError, "error generating subkey etype")
 		err = krberror.Errorf(err, krberror.KRBMsgError, "error generating subkey etype")
 		return
 		return
 	}
 	}
-	err = auth.GenerateSeqNumberAndSubKey(sessionKey.KeyType, etype.GetKeyByteSize())
+	err = auth.GenerateSeqNumberAndSubKey(etype.GetETypeID(), etype.GetKeyByteSize())
 	if err != nil {
 	if err != nil {
 		err = krberror.Errorf(err, krberror.KRBMsgError, "error generating subkey")
 		err = krberror.Errorf(err, krberror.KRBMsgError, "error generating subkey")
 		return
 		return
@@ -45,7 +45,6 @@ func ChangePasswdMsg(cname types.PrincipalName, realm, password string, tkt mess
 	}
 	}
 
 
 	// Form the KRBPriv encpart data
 	// Form the KRBPriv encpart data
-	//TODO set the SAddress field???
 	kp := messages.EncKrbPrivPart{
 	kp := messages.EncKrbPrivPart{
 		UserData:       chpwdb,
 		UserData:       chpwdb,
 		Timestamp:      auth.CTime,
 		Timestamp:      auth.CTime,
@@ -54,7 +53,6 @@ func ChangePasswdMsg(cname types.PrincipalName, realm, password string, tkt mess
 	}
 	}
 	kpriv := messages.NewKRBPriv(kp)
 	kpriv := messages.NewKRBPriv(kp)
 	err = kpriv.EncryptEncPart(k)
 	err = kpriv.EncryptEncPart(k)
-	//_, kp.UserData, err = etype.EncryptData(auth.SubKey.KeyValue, chpwdb)
 	if err != nil {
 	if err != nil {
 		err = krberror.Errorf(err, krberror.EncryptingError, "error encrypting change passwd data")
 		err = krberror.Errorf(err, krberror.EncryptingError, "error encrypting change passwd data")
 		return
 		return

+ 13 - 4
messages/KDCReq.go

@@ -83,17 +83,26 @@ type KDCReqBody struct {
 	AdditionalTickets []Ticket            `asn1:"explicit,optional,tag:11"`
 	AdditionalTickets []Ticket            `asn1:"explicit,optional,tag:11"`
 }
 }
 
 
-// NewASReq generates a new KRB_AS_REQ struct for a TGT request.
-func NewASReq(realm string, c *config.Config, cname types.PrincipalName) (ASReq, error) {
+// NewASReqForTGT generates a new KRB_AS_REQ struct for a TGT request.
+func NewASReqForTGT(realm string, c *config.Config, cname types.PrincipalName) (ASReq, error) {
 	sname := types.PrincipalName{
 	sname := types.PrincipalName{
 		NameType:   nametype.KRB_NT_SRV_INST,
 		NameType:   nametype.KRB_NT_SRV_INST,
 		NameString: []string{"krbtgt", realm},
 		NameString: []string{"krbtgt", realm},
 	}
 	}
-	return NewASReqForSName(realm, c, cname, sname)
+	return NewASReq(realm, c, cname, sname)
+}
+
+// NewASReq generates a new KRB_AS_REQ struct for a TGT request.
+func NewASReqForChgPasswd(realm string, c *config.Config, cname types.PrincipalName) (ASReq, error) {
+	sname := types.PrincipalName{
+		NameType:   nametype.KRB_NT_PRINCIPAL,
+		NameString: []string{"kadmin", "changepw"},
+	}
+	return NewASReq(realm, c, cname, sname)
 }
 }
 
 
 // NewASReqSNAME generates a new KRB_AS_REQ struct for a given SNAME.
 // NewASReqSNAME generates a new KRB_AS_REQ struct for a given SNAME.
-func NewASReqForSName(realm string, c *config.Config, cname, sname types.PrincipalName) (ASReq, error) {
+func NewASReq(realm string, c *config.Config, cname, sname types.PrincipalName) (ASReq, error) {
 	nonce, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt32))
 	nonce, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt32))
 	if err != nil {
 	if err != nil {
 		return ASReq{}, err
 		return ASReq{}, err

+ 5 - 0
testdata/test_vectors.go

@@ -103,9 +103,14 @@ var TestVectors = map[string]string{
 	"PAC_Server_Signature":           "100000001e251d98d552be7df384f550",
 	"PAC_Server_Signature":           "100000001e251d98d552be7df384f550",
 	"PAC_KDC_Signature":              "76ffffff340be28b48765d0519ee9346cf53d822",
 	"PAC_KDC_Signature":              "76ffffff340be28b48765d0519ee9346cf53d822",
 	"PAC_Kerb_Validation_Info_Trust": "01100800cccccccc000200000000000000000200c30bcc79e444d301ffffffffffffff7fffffffffffffff7fc764125a0842d301c7247c84d142d301ffffffffffffff7f12001200040002001600160008000200000000000c0002000000000010000200000000001400020000000000180002002e0000005204000001020000030000001c0002002002000000000000000000000000000000000000060008002000020008000a00240002002800020000000000000000001002000000000000000000000000000000000000000000000000000000000000010000002c00020034000200020000003800020009000000000000000900000074006500730074007500730065007200310000000b000000000000000b0000005400650073007400310020005500730065007200310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000056040000070000000102000007000000550400000700000004000000000000000300000055004400430000000500000000000000040000005500530045005200040000000104000000000005150000002057308834e7d1d0a2fb0444010000003000020007000000010000000101000000000012010000000400000001040000000000051500000062dc8db6c8705249b5459e75020000005304000007000020540400000700002000000000",
 	"PAC_Kerb_Validation_Info_Trust": "01100800cccccccc000200000000000000000200c30bcc79e444d301ffffffffffffff7fffffffffffffff7fc764125a0842d301c7247c84d142d301ffffffffffffff7f12001200040002001600160008000200000000000c0002000000000010000200000000001400020000000000180002002e0000005204000001020000030000001c0002002002000000000000000000000000000000000000060008002000020008000a00240002002800020000000000000000001002000000000000000000000000000000000000000000000000000000000000010000002c00020034000200020000003800020009000000000000000900000074006500730074007500730065007200310000000b000000000000000b0000005400650073007400310020005500730065007200310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000056040000070000000102000007000000550400000700000004000000000000000300000055004400430000000500000000000000040000005500530045005200040000000104000000000005150000002057308834e7d1d0a2fb0444010000003000020007000000010000000101000000000012010000000400000001040000000000051500000062dc8db6c8705249b5459e75020000005304000007000020540400000700002000000000",
+
+	"ChangePasswdData": "3036a00d040b6e657770617373776f7264a1163014a003020101a10d300b1b09746573747573657231a20d1b0b544553542e474f4b524235",
+	"Kpasswd_Req":      "037aff8002c16e8202bd308202b9a003020105a10302010ea20703050000000000a38201f1618201ed308201e9a003020105a10d1b0b544553542e474f4b524235a21d301ba003020101a11430121b066b61646d696e1b086368616e67657077a38201b2308201aea003020111a103020101a28201a00482019ca3de94df50e8e9fe7a8c9386f594f469bf08874407fc7b95ddcf22110ef63e62ff0ba3c31c3bb725dc1dde1f4c2f69a4973b4b43c9b4b31f71f676d5e8e7b4d7906b1dfacc9897d865b17f934fb96b802344463bb0746fdd39e9e48ff1b2665dc895a74d3d3aac89512b43bd8ead8f455b9b819cc6f6a34fb7c5975d7c2dbd4349524961215b98f33f5747f1e0c89f3b3637462308953940741ab7fc38ae817ba85800dd911bb78b42264f2d285c2a0a33ca21c1a3d281ec14614010db31c3e3f4d4622b799f97b3d31c4445411278fec62dd8e6e349db280aaa4419b53ef6fbc01f0206bcfea2cbe835b46764c03c138722e54dab53a1080e5d6c99f8cd7a948880677176cfc2d3800f9ef64d1ec4f8bdadc1ae409990c4855a82e265682e8ddaa6dea70a1d7855f3e1e766f5efe428dd6da71c585f5d17d8f81e8f2a4f4b2245f5ff2cc444a2a1ae5d16a15d588597219d5659da537f752ca9b572b635088b325b60e8e62fd99487872261f41dcc466516b89992d277bb8b3a1ca770671fca36dd33c3dd6dab643e6710280661029254054273151ccfca9aaddc55a481ae3081aba003020112a103020101a2819e04819be66387f971d751d7d3ebb6acd815a0991e0ed9f07e2643783e7961fb88127b31f767bf00d1d071a81858b101f4d45460412d8013228f942bc51891e95a06aefa8cedd95e5a3e6e65597c0f05c19ee54dc6dc00b1a3f9d7a95516b5e447c40cd5b462ed6b17a007670311efa44dbe939cab11072b9af1443c3203767bb1a3240542db06dffcaebcedd5c335bb295127bc0e6d99f2c1e87f68de1f547581b03081ada003020105a103020115a381a030819da003020112a103020101a2819004818df272b2726c8f31c578f3b4275bc283828716010a20f0c4369bff474fcf202537060a71edcbe8ba720d0d9b2bac26b58353dc5b2945570374928a819eb3526362eda328e704f1a5ebe3272eed0fa6a6aa7d0f32c4fc0bd2e4ea52a8834ea7b5fb018934df87c18ab625f5c07f6c28e202e0cec63bcc37b1d381d64937998c1bdcd1585695eeffb75f8ce9e736b3",
+	"Kpasswd_Rep":      "00ec0001008c6f8189308186a003020105a10302010fa27a3078a003020112a271046f57cb442fd321312aff0b2dcda70fe436812f9805611adf3403ab6cd7708604e86e77f765a8486864f0dbf8d5d065a63790370bc110ed1e3c7eae9890e02407e8a8b349703fed1e7f165e1261a822c5b3e6823c282884f59afeb9f84f2a9845994135dd307eb2f544874393c1c455d475583056a003020105a103020115a34a3048a003020112a241043fdd3edaf0b6cbcab5b663189bafc0a19e6cc03b3c59d989c403735748ebc36088bad852add0f62581eed515fc1f297324df4fa12cb94b7ad5db257165369db5",
 }
 }
 
 
 const (
 const (
+	TESTUSER1_PASSWORD            = "passwordvalue"
 	TESTUSER1_KEYTAB              = "05020000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80100110010698c4df8e9f60e7eea5a21bf4526ad25000000010000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80100120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de9000000010000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80200110010698c4df8e9f60e7eea5a21bf4526ad25000000020000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80200120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de9000000020000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d801001300102eb8501967a7886e1f0c63ac9be8c4a0000000010000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d802001300102eb8501967a7886e1f0c63ac9be8c4a0000000020000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d801001400208ad66f209bb07daa186f8a229830f5ba06a3a2a33638f4ec66e1d29324e417ee000000010000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d802001400208ad66f209bb07daa186f8a229830f5ba06a3a2a33638f4ec66e1d29324e417ee00000002000000430001000b544553542e474f4b52423500097465737475736572310000000159beb1d801001000184580fb91760dabe6f808c22c26494f644cb35d61d32c79e300000001000000430001000b544553542e474f4b52423500097465737475736572310000000159beb1d802001000184580fb91760dabe6f808c22c26494f644cb35d61d32c79e3000000020000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80100170010084768c373663b3bef1f6385883cf7ff000000010000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80200170010084768c373663b3bef1f6385883cf7ff00000002"
 	TESTUSER1_KEYTAB              = "05020000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80100110010698c4df8e9f60e7eea5a21bf4526ad25000000010000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80100120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de9000000010000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80200110010698c4df8e9f60e7eea5a21bf4526ad25000000020000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80200120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de9000000020000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d801001300102eb8501967a7886e1f0c63ac9be8c4a0000000010000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d802001300102eb8501967a7886e1f0c63ac9be8c4a0000000020000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d801001400208ad66f209bb07daa186f8a229830f5ba06a3a2a33638f4ec66e1d29324e417ee000000010000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d802001400208ad66f209bb07daa186f8a229830f5ba06a3a2a33638f4ec66e1d29324e417ee00000002000000430001000b544553542e474f4b52423500097465737475736572310000000159beb1d801001000184580fb91760dabe6f808c22c26494f644cb35d61d32c79e300000001000000430001000b544553542e474f4b52423500097465737475736572310000000159beb1d802001000184580fb91760dabe6f808c22c26494f644cb35d61d32c79e3000000020000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80100170010084768c373663b3bef1f6385883cf7ff000000010000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80200170010084768c373663b3bef1f6385883cf7ff00000002"
 	TESTUSER1_USERKRB5_AD_KEYTAB  = "05020000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040100170010084768c373663b3bef1f6385883cf7ff000000010000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040100110010528b8ba0ae5131fbf71f6ddc5870cdce000000010000004b0001000b555345522e474f4b52423500097465737475736572310000000159de7c04010012002016475f89eba70e62af20a20e7bf3ca4ccad5ae22485c93ffb133650bc6f12585000000010000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040100130010a3ddea306fa06c068bc3e1fcf4b280ca000000010000004b0001000b555345522e474f4b52423500097465737475736572310000000159de7c0401001400205d2a66a8af5142db59bcaabac8310777bf60a85e8881469e2063bba4dff0c00a000000010000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040200170010084768c373663b3bef1f6385883cf7ff000000020000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040200110010528b8ba0ae5131fbf71f6ddc5870cdce000000020000004b0001000b555345522e474f4b52423500097465737475736572310000000159de7c04020012002016475f89eba70e62af20a20e7bf3ca4ccad5ae22485c93ffb133650bc6f12585000000020000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040200130010a3ddea306fa06c068bc3e1fcf4b280ca000000020000004b0001000b555345522e474f4b52423500097465737475736572310000000159de7c0402001400205d2a66a8af5142db59bcaabac8310777bf60a85e8881469e2063bba4dff0c00a00000002"
 	TESTUSER1_USERKRB5_AD_KEYTAB  = "05020000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040100170010084768c373663b3bef1f6385883cf7ff000000010000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040100110010528b8ba0ae5131fbf71f6ddc5870cdce000000010000004b0001000b555345522e474f4b52423500097465737475736572310000000159de7c04010012002016475f89eba70e62af20a20e7bf3ca4ccad5ae22485c93ffb133650bc6f12585000000010000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040100130010a3ddea306fa06c068bc3e1fcf4b280ca000000010000004b0001000b555345522e474f4b52423500097465737475736572310000000159de7c0401001400205d2a66a8af5142db59bcaabac8310777bf60a85e8881469e2063bba4dff0c00a000000010000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040200170010084768c373663b3bef1f6385883cf7ff000000020000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040200110010528b8ba0ae5131fbf71f6ddc5870cdce000000020000004b0001000b555345522e474f4b52423500097465737475736572310000000159de7c04020012002016475f89eba70e62af20a20e7bf3ca4ccad5ae22485c93ffb133650bc6f12585000000020000003b0001000b555345522e474f4b52423500097465737475736572310000000159de7c040200130010a3ddea306fa06c068bc3e1fcf4b280ca000000020000004b0001000b555345522e474f4b52423500097465737475736572310000000159de7c0402001400205d2a66a8af5142db59bcaabac8310777bf60a85e8881469e2063bba4dff0c00a00000002"
 	TESTUSER1_WRONGPASSWD         = "0502000000370001000b544553542e474f4b52423500097465737475736572310000000158ef4bc5010011001039a9a382153105f8708e80f93382654e000000470001000b544553542e474f4b52423500097465737475736572310000000158ef4bc60100120020fc5bb940d6075214e0c6fc0456ce68c33306094198a927b4187d7cf3f4aea50d"
 	TESTUSER1_WRONGPASSWD         = "0502000000370001000b544553542e474f4b52423500097465737475736572310000000158ef4bc5010011001039a9a382153105f8708e80f93382654e000000470001000b544553542e474f4b52423500097465737475736572310000000158ef4bc60100120020fc5bb940d6075214e0c6fc0456ce68c33306094198a927b4187d7cf3f4aea50d"

+ 4 - 1
testenv/docker/krb5kdc/Dockerfile

@@ -2,7 +2,8 @@ FROM centos:latest
 MAINTAINER Jonathan Turner <jt@jtnet.co.uk>
 MAINTAINER Jonathan Turner <jt@jtnet.co.uk>
 
 
 EXPOSE 88
 EXPOSE 88
-ENTRYPOINT ["/usr/sbin/krb5kdc", "-n"]
+EXPOSE 464
+ENTRYPOINT ["/opt/krb5/bin/start.sh"]
 
 
 RUN yum install -y \
 RUN yum install -y \
   krb5-server \
   krb5-server \
@@ -13,7 +14,9 @@ ADD krb5.conf /etc/krb5.conf
 ADD kdc.conf /var/kerberos/krb5kdc/kdc.conf
 ADD kdc.conf /var/kerberos/krb5kdc/kdc.conf
 ADD kadm5.acl /var/kerberos/krb5kdc/kadm5.acl
 ADD kadm5.acl /var/kerberos/krb5kdc/kadm5.acl
 ADD krb5kdc-init.sh /opt/krb5/bin/krb5kdc-init.sh
 ADD krb5kdc-init.sh /opt/krb5/bin/krb5kdc-init.sh
+ADD start.sh /opt/krb5/bin/start.sh
 RUN mkdir -p /opt/krb5/log && \
 RUN mkdir -p /opt/krb5/log && \
   mkdir -p /var/log/kerberos && \
   mkdir -p /var/log/kerberos && \
+  chmod 744 /opt/krb5/bin/start.sh && \
   /bin/bash /opt/krb5/bin/krb5kdc-init.sh && \
   /bin/bash /opt/krb5/bin/krb5kdc-init.sh && \
   ln -sf /dev/stdout /var/log/krb5kdc.log
   ln -sf /dev/stdout /var/log/krb5kdc.log

+ 4 - 0
testenv/docker/krb5kdc/start.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+
+/usr/sbin/kadmind &
+/usr/sbin/krb5kdc -n

+ 0 - 1
testenv/krb5kdc-vagrant/kadm5.acl

@@ -1,5 +1,4 @@
 __ADMIN_USER__@__REALM__	*
 __ADMIN_USER__@__REALM__	*
 */admin@__REALM__	*
 */admin@__REALM__	*
 */*@__REALM__		i
 */*@__REALM__		i
-*@__REALM__     c   *1@__REALM__
 *@__REALM__		i
 *@__REALM__		i