Scott Baker | 2c1c482 | 2019-10-16 11:02:41 -0700 | [diff] [blame] | 1 | // Package messages implements Kerberos 5 message types and methods. |
| 2 | package messages |
| 3 | |
| 4 | import ( |
| 5 | "fmt" |
| 6 | "time" |
| 7 | |
| 8 | "github.com/jcmturner/gofork/encoding/asn1" |
| 9 | "gopkg.in/jcmturner/gokrb5.v7/iana" |
| 10 | "gopkg.in/jcmturner/gokrb5.v7/iana/asnAppTag" |
| 11 | "gopkg.in/jcmturner/gokrb5.v7/iana/errorcode" |
| 12 | "gopkg.in/jcmturner/gokrb5.v7/iana/msgtype" |
| 13 | "gopkg.in/jcmturner/gokrb5.v7/krberror" |
| 14 | "gopkg.in/jcmturner/gokrb5.v7/types" |
| 15 | ) |
| 16 | |
| 17 | // KRBError implements RFC 4120 KRB_ERROR: https://tools.ietf.org/html/rfc4120#section-5.9.1. |
| 18 | type KRBError struct { |
| 19 | PVNO int `asn1:"explicit,tag:0"` |
| 20 | MsgType int `asn1:"explicit,tag:1"` |
| 21 | CTime time.Time `asn1:"generalized,optional,explicit,tag:2"` |
| 22 | Cusec int `asn1:"optional,explicit,tag:3"` |
| 23 | STime time.Time `asn1:"generalized,explicit,tag:4"` |
| 24 | Susec int `asn1:"explicit,tag:5"` |
| 25 | ErrorCode int32 `asn1:"explicit,tag:6"` |
| 26 | CRealm string `asn1:"generalstring,optional,explicit,tag:7"` |
| 27 | CName types.PrincipalName `asn1:"optional,explicit,tag:8"` |
| 28 | Realm string `asn1:"generalstring,explicit,tag:9"` |
| 29 | SName types.PrincipalName `asn1:"explicit,tag:10"` |
| 30 | EText string `asn1:"generalstring,optional,explicit,tag:11"` |
| 31 | EData []byte `asn1:"optional,explicit,tag:12"` |
| 32 | } |
| 33 | |
| 34 | // NewKRBError creates a new KRBError. |
| 35 | func NewKRBError(sname types.PrincipalName, realm string, code int32, etext string) KRBError { |
| 36 | t := time.Now().UTC() |
| 37 | return KRBError{ |
| 38 | PVNO: iana.PVNO, |
| 39 | MsgType: msgtype.KRB_ERROR, |
| 40 | STime: t, |
| 41 | Susec: int((t.UnixNano() / int64(time.Microsecond)) - (t.Unix() * 1e6)), |
| 42 | ErrorCode: code, |
| 43 | SName: sname, |
| 44 | Realm: realm, |
| 45 | EText: etext, |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | // Unmarshal bytes b into the KRBError struct. |
| 50 | func (k *KRBError) Unmarshal(b []byte) error { |
| 51 | _, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBError)) |
| 52 | if err != nil { |
| 53 | return krberror.Errorf(err, krberror.EncodingError, "KRB_ERROR unmarshal error") |
| 54 | } |
| 55 | expectedMsgType := msgtype.KRB_ERROR |
| 56 | if k.MsgType != expectedMsgType { |
| 57 | return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate a KRB_ERROR. Expected: %v; Actual: %v", expectedMsgType, k.MsgType) |
| 58 | } |
| 59 | return nil |
| 60 | } |
| 61 | |
| 62 | // Error method implementing error interface on KRBError struct. |
| 63 | func (k KRBError) Error() string { |
| 64 | etxt := fmt.Sprintf("KRB Error: %s", errorcode.Lookup(k.ErrorCode)) |
| 65 | if k.EText != "" { |
| 66 | etxt = fmt.Sprintf("%s - %s", etxt, k.EText) |
| 67 | } |
| 68 | return etxt |
| 69 | } |
| 70 | |
| 71 | func processUnmarshalReplyError(b []byte, err error) error { |
| 72 | switch err.(type) { |
| 73 | case asn1.StructuralError: |
| 74 | var krberr KRBError |
| 75 | tmperr := krberr.Unmarshal(b) |
| 76 | if tmperr != nil { |
| 77 | return krberror.Errorf(err, krberror.EncodingError, "failed to unmarshal KDC's reply") |
| 78 | } |
| 79 | return krberr |
| 80 | default: |
| 81 | return krberror.Errorf(err, krberror.EncodingError, "failed to unmarshal KDC's reply") |
| 82 | } |
| 83 | } |