Skip to content

Commit 60d1ae5

Browse files
committed
Support compound requests
And use them to get security descriptor Also debug packets (will be temporal)
1 parent 28c7cf1 commit 60d1ae5

9 files changed

Lines changed: 588 additions & 139 deletions

File tree

client.go

Lines changed: 115 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,17 @@ func (fs *Share) SetSecurityInfoRaw(name string, flags SecurityInformationReques
11311131
FileId: f.fd,
11321132
}
11331133

1134-
_, err = fs.sendRecv(SMB2_SET_INFO, req)
1134+
req.CreditCharge, _, err = fs.loanCredit(req.Size())
1135+
defer func() {
1136+
if err != nil {
1137+
fs.chargeCredit(req.CreditCharge)
1138+
}
1139+
}()
1140+
if err != nil {
1141+
return fmt.Errorf("calling loanCredit: %w", err)
1142+
}
1143+
1144+
_, err = fs.sendRecv(req, SMB2_SET_INFO)
11351145
if err != nil {
11361146
return &os.PathError{Op: op, Path: name, Err: err}
11371147
}
@@ -1160,6 +1170,51 @@ func (fs *Share) SecurityInfoRaw2(name string, info SecurityInformationRequestFl
11601170
access |= ACCESS_SYSTEM_SECURITY
11611171
}
11621172

1173+
creq := &CreateRequest{
1174+
SecurityFlags: 0,
1175+
RequestedOplockLevel: SMB2_OPLOCK_LEVEL_NONE,
1176+
ImpersonationLevel: Impersonation,
1177+
SmbCreateFlags: 0,
1178+
DesiredAccess: access,
1179+
FileAttributes: FILE_ATTRIBUTE_NORMAL,
1180+
ShareAccess: FILE_SHARE_READ,
1181+
CreateDisposition: FILE_OPEN,
1182+
CreateOptions: 0,
1183+
Mapping: fs.mapping,
1184+
}
1185+
qreq := &QueryInfoRequest{
1186+
InfoType: SMB2_0_INFO_SECURITY, // TODO: rename info type constants to be more idiomatic with go
1187+
FileInfoClass: 0, // From the docs: "For security queries, this field MUST be set to 0"
1188+
OutputBufferLength: 64 * 1024, // Security descriptors have a max size of 64 KiB on NTFS: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntquerysecurityobject#remarks
1189+
AdditionalInformation: uint32(info),
1190+
Flags: 0,
1191+
FileId: &FileId{ // in compound requests, this value represents the result of the create request
1192+
Persistent: [8]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1193+
Volatile: [8]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1194+
},
1195+
}
1196+
req := NewCompoundPacket(creq, qreq)
1197+
1198+
var err error
1199+
creq.CreditCharge, _, err = fs.loanCredit(req.Size()) // put credit charge in first header
1200+
defer func() {
1201+
if err != nil {
1202+
fs.chargeCredit(creq.CreditCharge)
1203+
}
1204+
}()
1205+
if err != nil {
1206+
return nil, fmt.Errorf("calling loanCredit: %w", err)
1207+
}
1208+
1209+
rss, err := fs.sendRecv(req, SMB2_CREATE, SMB2_QUERY_INFO) // two expected commands for two requests in compound request
1210+
if err != nil {
1211+
return nil, &os.PathError{Op: op, Path: name, Err: err}
1212+
}
1213+
1214+
if len(rss) < 2 {
1215+
return nil, &os.PathError{Op: op, Path: name, Err: fmt.Errorf("expecting two commands in compound response, but got one")}
1216+
}
1217+
11631218
return nil, &os.PathError{Op: op, Path: name, Err: fmt.Errorf("compound security info not implemented yet")}
11641219
}
11651220

@@ -1184,12 +1239,15 @@ func (fs *Share) createFile(name string, req *CreateRequest, followSymlinks bool
11841239

11851240
req.Name = name
11861241

1187-
res, err := fs.sendRecv(SMB2_CREATE, req)
1242+
res, err := fs.sendRecv(req, SMB2_CREATE)
11881243
if err != nil {
11891244
return nil, fmt.Errorf("calling sendRecv: %w", err)
11901245
}
1246+
if len(res) == 0 {
1247+
return nil, &InvalidResponseError{"unexpected empty response"}
1248+
}
11911249

1192-
r := CreateResponseDecoder(res)
1250+
r := CreateResponseDecoder(res[0])
11931251
if r.IsInvalid() {
11941252
return nil, &InvalidResponseError{"broken create response format"}
11951253
}
@@ -1213,7 +1271,7 @@ func (fs *Share) createFileRec(name string, req *CreateRequest) (f *File, err er
12131271

12141272
req.Name = name
12151273

1216-
res, err := fs.sendRecv(SMB2_CREATE, req)
1274+
res, err := fs.sendRecv(req, SMB2_CREATE)
12171275
if err != nil {
12181276
if rerr, ok := err.(*ResponseError); ok && erref.NtStatus(rerr.Code) == erref.STATUS_STOPPED_ON_SYMLINK {
12191277
if len(rerr.data) > 0 {
@@ -1226,8 +1284,11 @@ func (fs *Share) createFileRec(name string, req *CreateRequest) (f *File, err er
12261284
}
12271285
return nil, fmt.Errorf("calling sendRecv SMB2_CREATE: %w", err)
12281286
}
1287+
if len(res) == 0 {
1288+
return nil, &InvalidResponseError{"unexpected empty response"}
1289+
}
12291290

1230-
r := CreateResponseDecoder(res)
1291+
r := CreateResponseDecoder(res[0])
12311292
if r.IsInvalid() {
12321293
return nil, &InvalidResponseError{"broken create response format"}
12331294
}
@@ -1267,18 +1328,18 @@ func evalSymlinkError(name string, errData []byte, mc utf16le.MapChars) (string,
12671328
return dir(ud) + target + u, nil
12681329
}
12691330

1270-
func (fs *Share) sendRecv(cmd uint16, req Packet) (res []byte, err error) {
1331+
func (fs *Share) sendRecv(req Packet, cmds ...uint16) (res [][]byte, err error) {
12711332
rr, err := fs.send(req, fs.ctx)
12721333
if err != nil {
12731334
return nil, err
12741335
}
12751336

1276-
pkt, err := fs.recv(rr)
1337+
pkts, err := fs.recv(rr)
12771338
if err != nil {
12781339
return nil, err
12791340
}
12801341

1281-
return accept(cmd, pkt)
1342+
return accept(pkts, cmds...)
12821343
}
12831344

12841345
func (fs *Share) loanCredit(payloadSize int) (creditCharge uint16, grantedPayloadSize int, err error) {
@@ -1326,12 +1387,15 @@ func (f *File) close() error {
13261387

13271388
req.FileId = f.fd
13281389

1329-
res, err := f.sendRecv(SMB2_CLOSE, req)
1390+
res, err := f.sendRecv(req, SMB2_CLOSE)
13301391
if err != nil {
13311392
return err
13321393
}
1394+
if len(res) == 0 {
1395+
return &InvalidResponseError{"unexpected empty response"}
1396+
}
13331397

1334-
r := CloseResponseDecoder(res)
1398+
r := CloseResponseDecoder(res[0])
13351399
if r.IsInvalid() {
13361400
return &InvalidResponseError{"broken close response format"}
13371401
}
@@ -1515,12 +1579,15 @@ func (f *File) readAtChunk(n int, off int64) (bs []byte, isEOF bool, err error)
15151579

15161580
req.CreditCharge = creditCharge
15171581

1518-
res, err := f.sendRecv(SMB2_READ, req)
1582+
res, err := f.sendRecv(req, SMB2_READ)
15191583
if err != nil {
15201584
return nil, false, err
15211585
}
1586+
if len(res) == 0 {
1587+
return nil, false, &InvalidResponseError{"unexpected empty response"}
1588+
}
15221589

1523-
r := ReadResponseDecoder(res)
1590+
r := ReadResponseDecoder(res[0])
15241591
if r.IsInvalid() {
15251592
return nil, false, &InvalidResponseError{"broken read response format"}
15261593
}
@@ -1769,12 +1836,15 @@ func (f *File) Sync() (err error) {
17691836
return &os.PathError{Op: "sync", Path: f.name, Err: err}
17701837
}
17711838

1772-
res, err := f.sendRecv(SMB2_FLUSH, req)
1839+
res, err := f.sendRecv(req, SMB2_FLUSH)
17731840
if err != nil {
17741841
return &os.PathError{Op: "sync", Path: f.name, Err: err}
17751842
}
1843+
if len(res) == 0 {
1844+
return &InvalidResponseError{"unexpected empty response"}
1845+
}
17761846

1777-
r := FlushResponseDecoder(res)
1847+
r := FlushResponseDecoder(res[0])
17781848
if r.IsInvalid() {
17791849
return &os.PathError{Op: "sync", Path: f.name, Err: &InvalidResponseError{"broken flush response format"}}
17801850
}
@@ -1949,12 +2019,15 @@ func (f *File) writeAtChunk(b []byte, off int64) (n int, err error) {
19492019

19502020
req.CreditCharge = creditCharge
19512021

1952-
res, err := f.sendRecv(SMB2_WRITE, req)
2022+
res, err := f.sendRecv(req, SMB2_WRITE)
19532023
if err != nil {
19542024
return 0, err
19552025
}
2026+
if len(res) == 0 {
2027+
return 0, &InvalidResponseError{"unexpected empty response"}
2028+
}
19562029

1957-
r := WriteResponseDecoder(res)
2030+
r := WriteResponseDecoder(res[0])
19582031
if r.IsInvalid() {
19592032
return 0, &InvalidResponseError{"broken write response format"}
19602033
}
@@ -2182,16 +2255,22 @@ func (f *File) ioctl(req *IoctlRequest) (output []byte, err error) {
21822255

21832256
req.FileId = f.fd
21842257

2185-
res, err := f.sendRecv(SMB2_IOCTL, req)
2258+
res, err := f.sendRecv(req, SMB2_IOCTL)
21862259
if err != nil {
2187-
r := IoctlResponseDecoder(res)
2260+
if len(res) == 0 {
2261+
return nil, err
2262+
}
2263+
r := IoctlResponseDecoder(res[0])
21882264
if r.IsInvalid() {
21892265
return nil, err
21902266
}
21912267
return r.Output(), err
21922268
}
2269+
if len(res) == 0 {
2270+
return nil, &InvalidResponseError{"unexpected empty response"}
2271+
}
21932272

2194-
r := IoctlResponseDecoder(res)
2273+
r := IoctlResponseDecoder(res[0])
21952274
if r.IsInvalid() {
21962275
return nil, &InvalidResponseError{"broken ioctl response format"}
21972276
}
@@ -2227,12 +2306,15 @@ func (f *File) readdir(pattern string) (fi []os.FileInfo, err error) {
22272306

22282307
req.FileId = f.fd
22292308

2230-
res, err := f.sendRecv(SMB2_QUERY_DIRECTORY, req)
2309+
res, err := f.sendRecv(req, SMB2_QUERY_DIRECTORY)
22312310
if err != nil {
22322311
return nil, err
22332312
}
2313+
if len(res) == 0 {
2314+
return nil, &InvalidResponseError{"unexpected empty response"}
2315+
}
22342316

2235-
r := QueryDirectoryResponseDecoder(res)
2317+
r := QueryDirectoryResponseDecoder(res[0])
22362318
if r.IsInvalid() {
22372319
return nil, &InvalidResponseError{"broken query directory response format"}
22382320
}
@@ -2291,12 +2373,15 @@ func (f *File) queryInfo(req *QueryInfoRequest) (infoBytes []byte, err error) {
22912373

22922374
req.FileId = f.fd
22932375

2294-
res, err := f.sendRecv(SMB2_QUERY_INFO, req)
2376+
res, err := f.sendRecv(req, SMB2_QUERY_INFO)
22952377
if err != nil {
22962378
return nil, err
22972379
}
2380+
if len(res) == 0 {
2381+
return nil, &InvalidResponseError{"unexpected empty response"}
2382+
}
22982383

2299-
r := QueryInfoResponseDecoder(res)
2384+
r := QueryInfoResponseDecoder(res[0])
23002385
if r.IsInvalid() {
23012386
return nil, &InvalidResponseError{"broken query info response format"}
23022387
}
@@ -2346,21 +2431,24 @@ func (f *File) setInfo(req *SetInfoRequest) (err error) {
23462431

23472432
req.InfoType = SMB2_0_INFO_FILE
23482433

2349-
res, err := f.sendRecv(SMB2_SET_INFO, req)
2434+
res, err := f.sendRecv(req, SMB2_SET_INFO)
23502435
if err != nil {
23512436
return err
23522437
}
2438+
if len(res) == 0 {
2439+
return &InvalidResponseError{"unexpected empty response"}
2440+
}
23532441

2354-
r := SetInfoResponseDecoder(res)
2442+
r := SetInfoResponseDecoder(res[0])
23552443
if r.IsInvalid() {
23562444
return &InvalidResponseError{"broken set info response format"}
23572445
}
23582446

23592447
return nil
23602448
}
23612449

2362-
func (f *File) sendRecv(cmd uint16, req Packet) (res []byte, err error) {
2363-
return f.fs.sendRecv(cmd, req)
2450+
func (f *File) sendRecv(req Packet, cmd uint16) (res [][]byte, err error) {
2451+
return f.fs.sendRecv(req, cmd)
23642452
}
23652453

23662454
type FileStat struct {

0 commit comments

Comments
 (0)