Skip to content

Commit 7c69d9b

Browse files
committed
make xmit size adjustable per bind request
1 parent 4a46d46 commit 7c69d9b

File tree

5 files changed

+42
-50
lines changed

5 files changed

+42
-50
lines changed

config/config.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,10 @@ type Config struct {
169169
Protocol string `json:"protocol"`
170170

171171
// The transfer encoding to use (ndr20, ndr64)
172-
TrasnferEncoding string `json:"transfer_encoding"`
172+
TransferEncoding string `json:"transfer_encoding"`
173+
174+
// The transfer window size.
175+
TransportXmitSize int `json:"transport_xmit_size"`
173176

174177
// The flag that indicates whether credentials and mechanisms should be
175178
// included into connection options. If GlobalCredentials is true, then
@@ -203,7 +206,8 @@ func New() *Config {
203206
cfg.Auth.KRB5.DisablePAFXFAST = true
204207
cfg.Auth.KRB5.AnyServiceClassSPN = true
205208

206-
cfg.TrasnferEncoding = "ndr20"
209+
cfg.TransferEncoding = "ndr20"
210+
cfg.TransportXmitSize = dcerpc.DefaultXmitSize
207211

208212
return cfg
209213
}
@@ -373,7 +377,7 @@ func (cfg *Config) ClientOptions(ctx context.Context) []dcerpc.Option {
373377

374378
options := []dcerpc.Option{}
375379

376-
switch cfg.TrasnferEncoding {
380+
switch cfg.TransferEncoding {
377381
case "ndr20":
378382
options = append(options, dcerpc.WithNDR20())
379383
case "ndr64":
@@ -513,6 +517,10 @@ func (cfg *Config) getDialOptions() []dcerpc.Option {
513517
options = append(options, dcerpc.WithSMBDialer(smb2.NewDialer(dialer...)))
514518
}
515519

520+
if cfg.TransportXmitSize > 0 {
521+
options = append(options, dcerpc.WithFragmentSize(cfg.TransportXmitSize))
522+
}
523+
516524
if !cfg.useGlobalCredentials {
517525
if cfg.useMachineAccount {
518526
for _, cred := range cfg.MachineAccountCredentials() {
@@ -733,9 +741,9 @@ func (cfg *Config) ParseServerAddr() error {
733741
switch extra {
734742
// transfer encoding.
735743
case "ndr20":
736-
cfg.TrasnferEncoding = "ndr20"
744+
cfg.TransferEncoding = "ndr20"
737745
case "ndr64":
738-
cfg.TrasnferEncoding = "ndr64"
746+
cfg.TransferEncoding = "ndr64"
739747
// auth type keywords.
740748
case "spnego":
741749
cfg.Auth.SPNEGO = true
@@ -806,10 +814,14 @@ func (cfg *Config) Validate() error {
806814
}
807815
}
808816

809-
if err := ValidateTransferEncoding(cfg.TrasnferEncoding); err != nil {
817+
if err := ValidateTransferEncoding(cfg.TransferEncoding); err != nil {
810818
return err
811819
}
812820

821+
if cfg.TransportXmitSize <= 1024 {
822+
return fmt.Errorf("transport xmit size must be greater than 1024")
823+
}
824+
813825
if err := ValidateAuthLevel(cfg.Auth.Level); err != nil {
814826
return err
815827
}

config/flag/command_line.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ func BindFlags(c *config.Config, flagSet *flag.FlagSet) {
1818

1919
flagSet.DurationVar(&c.Timeout, "timeout", c.Timeout, "timeout")
2020

21-
flagSet.StringVar(&c.TrasnferEncoding, "transfer-encoding", c.TrasnferEncoding, "transfer encoding: ndr20, ndr64")
21+
flagSet.StringVar(&c.TransferEncoding, "transfer-encoding", c.TransferEncoding, "transfer encoding: ndr20, ndr64")
22+
flagSet.IntVar(&c.TransportXmitSize, "transport-xmit-size", c.TransportXmitSize, "transport xmit size")
2223

2324
flagSet.StringVar(&c.Credential.Password, "password", c.Credential.Password, "password to authenticate with")
2425
flagSet.StringVar(&c.Credential.NTHash, "nthash", c.Credential.NTHash, "NT hash to authenticate with")

dcerpc/pdu.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ type AlterContext struct {
106106
}
107107

108108
func (pdu *AlterContext) Size() int {
109-
size := 8 + 1
109+
size := 8 + 4
110110
for _, ctx := range pdu.ContextList {
111111
size += ctx.Size()
112112
}
@@ -214,7 +214,7 @@ type Bind struct {
214214
}
215215

216216
func (pdu *Bind) Size() int {
217-
size := 8 + 1
217+
size := 8 + 4
218218
for _, ctx := range pdu.ContextList {
219219
size += ctx.Size()
220220
}
@@ -325,6 +325,8 @@ func (pdu *BindNak) Error() string {
325325
return "bind: authentication type was not recognized"
326326
case InvalidChecksum:
327327
return "bind: invalid checksum"
328+
case ProtocolVersionNotSupported:
329+
return "bind: protocol version not supported"
328330
default:
329331
return "bind: unknown error"
330332
}

dcerpc/transport.go

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -150,41 +150,6 @@ func (c *transport) ExportSMBSecurity(o *Security) {
150150
o.SetAttribute(gssapi.AttributeSMBEffectiveSessionKey, pipe.SessionKey())
151151
}
152152
}
153-
154-
}
155-
156-
// writePacketFragmentedAuth writes the packet with fragmented authentication data.
157-
func (c *transport) writePacketFragmentedAuth(ctx context.Context, call Call, pkt *Packet) error {
158-
159-
authData, maxSize := pkt.AuthData, c.settings.MaxXmitFrag-pkt.PDUHeaderSize()
160-
161-
// https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm:
162-
//
163-
// If pfc_flags does not have PFC_LAST_FRAG set and rpc_vers_minor is 1,
164-
// then the PDU has fragmented auth_verifier data. The server will assemble
165-
// the data concatenating sequentially each auth_verifier field until a
166-
// PDU is sent with PFC_LAST_FRAG flag set. This completed buffer is then
167-
// used as auth_verifier data.
168-
169-
for {
170-
171-
if pkt.Set(PacketFlagLastFrag); len(authData) > maxSize {
172-
pkt.AuthData, authData = authData[:maxSize], authData[maxSize:]
173-
pkt.Header.RPCVersionMinor = 1
174-
pkt.Unset(PacketFlagLastFrag)
175-
}
176-
177-
// write bind pdu.
178-
if err := c.WritePacket(ctx, call, pkt); err != nil {
179-
return fmt.Errorf("alter context: write packet: %w", err)
180-
}
181-
182-
if pkt.Unset(PacketFlagFirstFrag); len(pkt.AuthData) <= maxSize {
183-
break
184-
}
185-
}
186-
187-
return nil
188153
}
189154

190155
// AlterContext function establishes new presentation or security (or both) context(s).
@@ -229,7 +194,7 @@ func (c *transport) AlterContext(ctx context.Context, opts ...Option) (Conn, err
229194
}
230195

231196
// write alter-context pdu.
232-
if err := c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
197+
if err := c.WritePacket(ctx, call, pkt); err != nil {
233198
return nil, err
234199
}
235200

@@ -279,14 +244,14 @@ func (c *transport) AlterContext(ctx context.Context, opts ...Option) (Conn, err
279244
// replace type with auth3.
280245
pkt.PDU = &Auth3{}
281246
// write auth3 pdu.
282-
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
247+
if err = c.WritePacket(ctx, call, pkt); err != nil {
283248
return nil, fmt.Errorf("alter context: auth3: write packet: %w", err)
284249
}
285250
// no response is assumed.
286251
break
287252
}
288253
// write alter_context request.
289-
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
254+
if err = c.WritePacket(ctx, call, pkt); err != nil {
290255
return nil, fmt.Errorf("alter context: write packet: %w", err)
291256
}
292257
// read alter_context response.
@@ -420,8 +385,19 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {
420385
if pkt.AuthData, err = o.Security.Init(ctx, nil); err != nil {
421386
return nil, fmt.Errorf("bind: %w", err)
422387
}
388+
389+
// XXX: adjust max xmit frag size if auth data is too large.
390+
if len(pkt.AuthData) > c.settings.MaxXmitFrag-pkt.PDUHeaderSize() {
391+
c.logger.Warn().Int("auth_data_size", len(pkt.AuthData)).
392+
Int("previous_max_xmit_frag", c.settings.MaxXmitFrag).
393+
Msg("adjusting max xmit frag size to fit auth data")
394+
c.settings.MaxXmitFrag = len(pkt.AuthData) + pkt.PDUHeaderSize()
395+
// reset buffered connector.
396+
c.cc = c.cc.Resized(c.settings.FragmentSize())
397+
}
398+
423399
// write bind pdu.
424-
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
400+
if err = c.WritePacket(ctx, call, pkt); err != nil {
425401
return nil, fmt.Errorf("bind: write packet: %w", err)
426402
}
427403
// read bind response (bind-ack, bind-nak).
@@ -499,14 +475,14 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {
499475
// replace type with auth3.
500476
pkt.PDU = &Auth3{}
501477
// write auth3 pdu.
502-
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
478+
if err = c.WritePacket(ctx, call, pkt); err != nil {
503479
return nil, fmt.Errorf("bind: alter context: auth3: write packet: %w", err)
504480
}
505481
// no response is assumed.
506482
break
507483
}
508484
// write alter_context request.
509-
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
485+
if err = c.WritePacket(ctx, call, pkt); err != nil {
510486
return nil, fmt.Errorf("bind: alter context: write packet: %w", err)
511487
}
512488
// read alter_context response.

dcerpc/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ const (
152152
AbstractSyntaxNotSupported ProviderReason = 0x0001
153153
ProposedTransferSyntaxesNotSupported ProviderReason = 0x0002
154154
LocalLimitExceeded ProviderReason = 0x0003
155+
ProtocolVersionNotSupported ProviderReason = 0x0004
155156
AuthTypeNotRecognized ProviderReason = 0x0008
156157
InvalidChecksum ProviderReason = 0x0009
157158

0 commit comments

Comments
 (0)