shithub: libdp9ik

ref: 7e77582b6904979700dde6b0cba53f2d91e2b28d

View raw version
package libdp9ik

import (
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
)

const (
	AuthTreq   = 1
	AuthChal   = 2
	AuthPass   = 3
	AuthOK     = 4
	AuthErr    = 5
	AuthMod    = 6
	AuthApop   = 7
	AuthOKvar  = 9
	AuthChap   = 10
	AuthMSchap = 11
	AuthCram   = 12
	AuthHttp   = 13
	AuthVNC    = 14
	AuthPAK    = 19
	AuthTs     = 64
	AuthTc     = 65
	AuthAs     = 66
	AuthAc     = 67
	AuthTp     = 68
	AuthHr     = 69
)

type TicketReq struct {
	Which   byte
	Authid  [Anamelen]byte
	Authdom [Domlen]byte
	Chal    [Challen]byte
	Hostid  [Anamelen]byte
	Uid     [Anamelen]byte
}

func (t *TicketReq) String() string {
	b := &strings.Builder{}
	b.WriteString(fmt.Sprintf("Which: %v\n", t.Which))
	b.WriteString("AuthID: " + string(t.Authid[:]) + "\n")
	b.WriteString("AuthDom: " + string(t.Authdom[:]) + "\n")
	b.WriteString(fmt.Sprintf("Chal: %v\n", t.Chal))
	b.WriteString(fmt.Sprintf("HostID: %v\n", t.Hostid))
	b.WriteString(fmt.Sprintf("UID: %v\n", t.Uid))

	return b.String()
}

func (t *TicketReq) UnmarshalBinary(data []byte) error {
	n := 0
	move := func(dst []byte, width int) {
		copy(dst, data[n:n+width])
		n += width
	}
	t.Which = data[n]
	n++
	move(t.Authid[:], Anamelen)
	move(t.Authdom[:], Domlen)
	move(t.Chal[:], Challen)
	move(t.Hostid[:], Anamelen)
	move(t.Uid[:], Anamelen)

	return nil
}

func (t *TicketReq) MarshalBinary() ([]byte, error) {
	size := 1 + Anamelen + Domlen + Challen + Anamelen + Anamelen
	out := make([]byte, size)
	n := 0

	out[0] = t.Which
	n++
	move := func(src []byte, width int) {
		copy(out[n:n+width], src)
		n += width
	}
	move(t.Authid[:], Anamelen)
	move(t.Authdom[:], Domlen)
	move(t.Chal[:], Challen)
	move(t.Hostid[:], Anamelen)
	move(t.Uid[:], Anamelen)
	return out, nil
}

type Ticket struct {
	Num  byte           /* replay protection */
	Chal [Challen]byte  /* server challenge */
	Cuid [Anamelen]byte /* uid on client */
	Suid [Anamelen]byte /* uid on server */
	Key  [Noncelen]byte /* nonce key */

	Form byte /* (not transmitted) format (0 = des, 1 = ccpoly) */
}

func convM2T(ap []byte, ak *AuthKey) (*Ticket, error) {
	t := &Ticket{}
	buf := make([]byte, Maxticketlen)
	//skipping libauthsrv/convM2t.c:20 check, this seems to be only for p9sk1
	m := 12 + Challen + 2*Anamelen + Noncelen + 16
	t.Form = 1
	copy(buf, ap)

}

func asrdresp(fd io.ReadWriter, buf []byte) error {
	errmsg := make([]byte, 64)
	_, err := fd.Read(buf[:1])
	if err != nil {
		return err
	}
	switch buf[0] {
	case AuthOK:
		_, err = fd.Read(buf)
		return err
	case AuthErr:
		_, err = fd.Read(errmsg)
		if err != nil {
			return err
		}
		return errors.New(string(errmsg))
	case AuthOKvar:
		_, err = fd.Read(errmsg[:5])
		if err != nil {
			return err
		}
		n, err := strconv.Atoi(string(errmsg[:5]))
		if err != nil {
			return err
		}
		_, err = fd.Read(buf[:n])
		if err != nil {
			return err
		}
	default:
		return errors.New("unknown Which from auth server")
	}
	return nil
}

func (tr *TicketReq) asgetticket(asfd io.ReadWriter, tbuf []byte) error {
	err := tr.asrequest(asfd)
	if err != nil {
		return err
	}
	err = asrdresp(asfd, tbuf)
	if err != nil {
		return err
	}

	//According to libauthsrv/ticket.c:20 in drawterm this is suppsoed
	//to try and pull some more data, however it seems like in the
	//case of a client(our case) it is never needed so we simply ignore
	//it as being a dp9ik server is outside our scope

	return nil
}

func (tr *TicketReq) asrequest(asfd io.ReadWriter) error {
	b, _ := tr.MarshalBinary()
	_, err := asfd.Write(b)
	return err
}