mirror of
https://github.com/oiweiwei/go-msrpc
synced 2026-06-08 16:28:58 +00:00
feat: support large kerberos tokens (#83)
* feat: fix auth too large * fix: alter-context large token
This commit is contained in:
@@ -3,3 +3,4 @@ rpc/y.out
|
||||
develop/.vagrant
|
||||
examples/testing
|
||||
test/
|
||||
.vimrc
|
||||
|
||||
+18
-6
@@ -169,7 +169,10 @@ type Config struct {
|
||||
Protocol string `json:"protocol"`
|
||||
|
||||
// The transfer encoding to use (ndr20, ndr64)
|
||||
TrasnferEncoding string `json:"transfer_encoding"`
|
||||
TransferEncoding string `json:"transfer_encoding"`
|
||||
|
||||
// The transfer window size.
|
||||
TransportXmitSize int `json:"transport_xmit_size"`
|
||||
|
||||
// The flag that indicates whether credentials and mechanisms should be
|
||||
// included into connection options. If GlobalCredentials is true, then
|
||||
@@ -203,7 +206,8 @@ func New() *Config {
|
||||
cfg.Auth.KRB5.DisablePAFXFAST = true
|
||||
cfg.Auth.KRB5.AnyServiceClassSPN = true
|
||||
|
||||
cfg.TrasnferEncoding = "ndr20"
|
||||
cfg.TransferEncoding = "ndr20"
|
||||
cfg.TransportXmitSize = dcerpc.DefaultXmitSize
|
||||
|
||||
return cfg
|
||||
}
|
||||
@@ -373,7 +377,7 @@ func (cfg *Config) ClientOptions(ctx context.Context) []dcerpc.Option {
|
||||
|
||||
options := []dcerpc.Option{}
|
||||
|
||||
switch cfg.TrasnferEncoding {
|
||||
switch cfg.TransferEncoding {
|
||||
case "ndr20":
|
||||
options = append(options, dcerpc.WithNDR20())
|
||||
case "ndr64":
|
||||
@@ -513,6 +517,10 @@ func (cfg *Config) getDialOptions() []dcerpc.Option {
|
||||
options = append(options, dcerpc.WithSMBDialer(smb2.NewDialer(dialer...)))
|
||||
}
|
||||
|
||||
if cfg.TransportXmitSize > 0 {
|
||||
options = append(options, dcerpc.WithFragmentSize(cfg.TransportXmitSize))
|
||||
}
|
||||
|
||||
if !cfg.useGlobalCredentials {
|
||||
if cfg.useMachineAccount {
|
||||
for _, cred := range cfg.MachineAccountCredentials() {
|
||||
@@ -733,9 +741,9 @@ func (cfg *Config) ParseServerAddr() error {
|
||||
switch extra {
|
||||
// transfer encoding.
|
||||
case "ndr20":
|
||||
cfg.TrasnferEncoding = "ndr20"
|
||||
cfg.TransferEncoding = "ndr20"
|
||||
case "ndr64":
|
||||
cfg.TrasnferEncoding = "ndr64"
|
||||
cfg.TransferEncoding = "ndr64"
|
||||
// auth type keywords.
|
||||
case "spnego":
|
||||
cfg.Auth.SPNEGO = true
|
||||
@@ -806,10 +814,14 @@ func (cfg *Config) Validate() error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := ValidateTransferEncoding(cfg.TrasnferEncoding); err != nil {
|
||||
if err := ValidateTransferEncoding(cfg.TransferEncoding); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cfg.TransportXmitSize <= 1024 {
|
||||
return fmt.Errorf("transport xmit size must be greater than 1024")
|
||||
}
|
||||
|
||||
if err := ValidateAuthLevel(cfg.Auth.Level); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ func BindFlags(c *config.Config, flagSet *flag.FlagSet) {
|
||||
|
||||
flagSet.DurationVar(&c.Timeout, "timeout", c.Timeout, "timeout")
|
||||
|
||||
flagSet.StringVar(&c.TrasnferEncoding, "transfer-encoding", c.TrasnferEncoding, "transfer encoding: ndr20, ndr64")
|
||||
flagSet.StringVar(&c.TransferEncoding, "transfer-encoding", c.TransferEncoding, "transfer encoding: ndr20, ndr64")
|
||||
|
||||
flagSet.IntVar(&c.TransportXmitSize, "transport-xmit-size", c.TransportXmitSize, "transport xmit size")
|
||||
|
||||
flagSet.StringVar(&c.Credential.Password, "password", c.Credential.Password, "password to authenticate with")
|
||||
flagSet.StringVar(&c.Credential.NTHash, "nthash", c.Credential.NTHash, "NT hash to authenticate with")
|
||||
|
||||
+8
-4
@@ -25,11 +25,15 @@ type BufferedConn struct {
|
||||
cur, total []byte
|
||||
}
|
||||
|
||||
func (conn *BufferedConn) Resized(sz int) *BufferedConn {
|
||||
if sz > len(conn.total) {
|
||||
conn.total = make([]byte, sz)
|
||||
func resizeBuffer(buf []byte, sz int) []byte {
|
||||
if sz > len(buf) {
|
||||
return make([]byte, sz)
|
||||
}
|
||||
conn.cur, conn.total = nil, conn.total[:sz]
|
||||
return buf[:sz]
|
||||
}
|
||||
|
||||
func (conn *BufferedConn) Resized(sz int) *BufferedConn {
|
||||
conn.cur, conn.total = nil, resizeBuffer(conn.total, sz)
|
||||
return conn
|
||||
}
|
||||
|
||||
|
||||
+27
-3
@@ -38,6 +38,21 @@ type Packet struct {
|
||||
start, end int
|
||||
}
|
||||
|
||||
func (p *Packet) Unset(flag PacketFlag) {
|
||||
p.Header.PacketFlags &^= flag
|
||||
}
|
||||
|
||||
func (p *Packet) Set(flag PacketFlag) {
|
||||
p.Header.PacketFlags |= flag
|
||||
}
|
||||
|
||||
func (p *Packet) PDUHeaderSize() int {
|
||||
if sizer := p.PDU.(interface{ Size() int }); sizer != nil {
|
||||
return HeaderSize + sizer.Size() + MaxPad + SecurityTrailerSize
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *Packet) IsLastFrag() bool {
|
||||
return p.Header.PacketFlags&PacketFlagLastFrag != 0
|
||||
}
|
||||
@@ -332,7 +347,7 @@ func (c *transport) EncodePacket(ctx context.Context, pkt *Packet, raw []byte) e
|
||||
pkt.raw, pkt.end = raw, len(raw)
|
||||
|
||||
// set packet rpc version.
|
||||
pkt.Header.RPCVersion, pkt.Header.RPCVersionMinor = 5, 0
|
||||
pkt.Header.RPCVersion = 5
|
||||
// set packet drep.
|
||||
pkt.Header.PacketDRep = c.settings.DataRepresentation
|
||||
// set packet type.
|
||||
@@ -364,14 +379,23 @@ func (c *transport) EncodePacket(ctx context.Context, pkt *Packet, raw []byte) e
|
||||
|
||||
// adjust stub buffer to include security trailer.
|
||||
if pkt.Header.AuthLength > 0 {
|
||||
pkt.end -= MaxPad + SecurityTrailerSize + int(pkt.Header.AuthLength)
|
||||
sz := MaxPad + SecurityTrailerSize + int(pkt.Header.AuthLength)
|
||||
if pkt.end -= sz; pkt.end <= 0 {
|
||||
if pkt.end, raw = cap(raw)-sz, raw[:cap(raw)]; pkt.end <= 0 || pkt.Header.PacketType != PacketTypeAlterContext {
|
||||
// XXX: allow exceeding capacity for alter-context requests (as they may contain large krb tickets)
|
||||
return fmt.Errorf("encode_packet: insufficient buffer size for security trailer (%d bytes)", sz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: verification is computed for every fragment, however it's being
|
||||
// written only for last fragment.
|
||||
verifyLen := pkt.VerificationTrailer.Size()
|
||||
if verifyLen > 0 {
|
||||
pkt.end -= VerificationTrailerMaxPad + verifyLen /* VerificationMaxPad */
|
||||
sz := VerificationTrailerMaxPad + verifyLen /* VerificationMaxPad */
|
||||
if pkt.end -= sz; pkt.end <= 0 {
|
||||
return fmt.Errorf("encode_packet: insufficient buffer size for verification trailer (%d bytes)", verifyLen)
|
||||
}
|
||||
}
|
||||
|
||||
w := c.Codec(raw, pkt.Header.PacketDRep)
|
||||
|
||||
@@ -70,6 +70,10 @@ type Auth3 struct {
|
||||
Pad [4]byte
|
||||
}
|
||||
|
||||
func (pdu *Auth3) Size() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (pdu *Auth3) MarshalZerologObject(e *zerolog.Event) {}
|
||||
|
||||
// marshal function ...
|
||||
@@ -101,6 +105,14 @@ type AlterContext struct {
|
||||
ContextList []*Context
|
||||
}
|
||||
|
||||
func (pdu *AlterContext) Size() int {
|
||||
size := 8 + 4
|
||||
for _, ctx := range pdu.ContextList {
|
||||
size += ctx.Size()
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (pdu *AlterContext) MarshalZerologObject(e *zerolog.Event) {}
|
||||
|
||||
func (pdu *AlterContext) WriteTo(ctx context.Context, w ndr.Writer) error {
|
||||
@@ -201,6 +213,14 @@ type Bind struct {
|
||||
ContextList []*Context
|
||||
}
|
||||
|
||||
func (pdu *Bind) Size() int {
|
||||
size := 8 + 4
|
||||
for _, ctx := range pdu.ContextList {
|
||||
size += ctx.Size()
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (pdu *Bind) MarshalZerologObject(e *zerolog.Event) {}
|
||||
|
||||
func (pdu *Bind) WriteTo(ctx context.Context, w ndr.Writer) error {
|
||||
@@ -305,6 +325,8 @@ func (pdu *BindNak) Error() string {
|
||||
return "bind: authentication type was not recognized"
|
||||
case InvalidChecksum:
|
||||
return "bind: invalid checksum"
|
||||
case ProtocolVersionNotSupported:
|
||||
return "bind: protocol version not supported"
|
||||
default:
|
||||
return "bind: unknown error"
|
||||
}
|
||||
|
||||
+21
-11
@@ -154,7 +154,6 @@ func (c *transport) ExportSMBSecurity(o *Security) {
|
||||
o.SetAttribute(gssapi.AttributeSMBEffectiveSessionKey, pipe.SessionKey())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// AlterContext function establishes new presentation or security (or both) context(s).
|
||||
@@ -197,11 +196,13 @@ func (c *transport) AlterContext(ctx context.Context, opts ...Option) (Conn, err
|
||||
if pkt.AuthData, err = o.Security.Init(ctx, nil); err != nil {
|
||||
return nil, fmt.Errorf("alter context: init security: %w", err)
|
||||
}
|
||||
// write bind pdu.
|
||||
if err = c.WritePacket(ctx, call, pkt); err != nil {
|
||||
return nil, fmt.Errorf("alter context: write packet: %w", err)
|
||||
|
||||
// write alter-context pdu.
|
||||
if err := c.WritePacket(ctx, call, pkt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// read bind response (bind-ack, bind-nak).
|
||||
|
||||
// read alter-context response (alter-context-response).
|
||||
if pkt, err = c.ReadPacket(ctx, call, pkt); err != nil {
|
||||
return nil, fmt.Errorf("alter context: read packet: %w", err)
|
||||
}
|
||||
@@ -389,6 +390,18 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {
|
||||
if pkt.AuthData, err = o.Security.Init(ctx, nil); err != nil {
|
||||
return nil, fmt.Errorf("bind: %w", err)
|
||||
}
|
||||
|
||||
// XXX: adjust max xmit frag size if auth data is too large.
|
||||
if len(pkt.AuthData) > c.settings.MaxXmitFrag-pkt.PDUHeaderSize() {
|
||||
c.logger.Warn().Int("auth_data_size", len(pkt.AuthData)).
|
||||
Int("max_xmit_frag", c.settings.MaxXmitFrag).
|
||||
Msg("adjusting transmit buffer size to fit auth data")
|
||||
sz := len(pkt.AuthData) + pkt.PDUHeaderSize()
|
||||
c.settings.MaxXmitFrag = sz
|
||||
// reset buffered connector.
|
||||
c.cc, c.tx, c.rx = c.cc.Resized(sz), resizeBuffer(c.tx, sz), resizeBuffer(c.rx, sz)
|
||||
}
|
||||
|
||||
// write bind pdu.
|
||||
if err = c.WritePacket(ctx, call, pkt); err != nil {
|
||||
return nil, fmt.Errorf("bind: write packet: %w", err)
|
||||
@@ -402,11 +415,6 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {
|
||||
|
||||
case *BindAck:
|
||||
|
||||
if c.settings.MaxRecvFrag != int(pdu.MaxRecvFrag) {
|
||||
// reset buffered connector.
|
||||
c.cc = c.cc.Resized(int(pdu.MaxRecvFrag))
|
||||
}
|
||||
|
||||
sz := c.settings.FragmentSize()
|
||||
|
||||
// save retrieved parameters.
|
||||
@@ -419,7 +427,9 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {
|
||||
o.Group.SetID(int(pdu.AssocGroupID))
|
||||
|
||||
if sz != c.settings.FragmentSize() {
|
||||
c.tx, c.rx = make([]byte, c.settings.FragmentSize()), make([]byte, c.settings.FragmentSize())
|
||||
c.tx, c.rx = resizeBuffer(c.tx, c.settings.FragmentSize()), resizeBuffer(c.rx, c.settings.FragmentSize())
|
||||
// reset buffered connector.
|
||||
c.cc = c.cc.Resized(c.settings.FragmentSize())
|
||||
}
|
||||
|
||||
// save negotiated header sign parameter.
|
||||
|
||||
@@ -112,7 +112,10 @@ func (c *call) WriteBuffer(ctx context.Context, hdr Header, p []byte) error {
|
||||
func (c *transport) WriteBuffer(ctx context.Context, hdr Header, p []byte) error {
|
||||
|
||||
if int(hdr.FragLength) > c.settings.MaxXmitFrag {
|
||||
return ErrPacketTooLong
|
||||
if hdr.PacketType != PacketTypeAlterContext {
|
||||
// XXX: allow exceeding capacity for alter-context requests (as they may contain large krb tickets)
|
||||
return ErrPacketTooLong
|
||||
}
|
||||
}
|
||||
|
||||
p = p[:hdr.FragLength]
|
||||
|
||||
@@ -14,6 +14,10 @@ type SyntaxID struct {
|
||||
IfVersionMinor uint16
|
||||
}
|
||||
|
||||
func (v *SyntaxID) Size() int {
|
||||
return 16 + 2 + 2
|
||||
}
|
||||
|
||||
func (v *SyntaxID) Is(other *SyntaxID) bool {
|
||||
if v == nil || other == nil {
|
||||
return false
|
||||
@@ -85,6 +89,14 @@ type Context struct {
|
||||
TransferSyntaxes []*SyntaxID
|
||||
}
|
||||
|
||||
func (c *Context) Size() int {
|
||||
size := 4 + c.AbstractSyntax.Size()
|
||||
for i := range c.TransferSyntaxes {
|
||||
size += c.TransferSyntaxes[i].Size()
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// marshal function ...
|
||||
func (c *Context) WriteTo(ctx context.Context, w ndr.Writer) error {
|
||||
w.WriteData(c.ContextID)
|
||||
@@ -140,6 +152,7 @@ const (
|
||||
AbstractSyntaxNotSupported ProviderReason = 0x0001
|
||||
ProposedTransferSyntaxesNotSupported ProviderReason = 0x0002
|
||||
LocalLimitExceeded ProviderReason = 0x0003
|
||||
ProtocolVersionNotSupported ProviderReason = 0x0004
|
||||
AuthTypeNotRecognized ProviderReason = 0x0008
|
||||
InvalidChecksum ProviderReason = 0x0009
|
||||
|
||||
|
||||
Reference in New Issue
Block a user