mirror of
https://github.com/gravitational/teleport
synced 2024-10-20 01:03:40 +00:00
Windows Desktop Directory Sharing (#13630)
* `IRP_MJ_CREATE` (#12665) * `IRP_MJ_QUERY_INFORMATION` (#12717) * `IRP_MJ_CLOSE` (#12729) * Refactor rdpdr client (#12750) * Adding logic for `FILE_SUPERSEDE` (#12829) * Improve `process_irp_create` (#12830) * adds return statements that got lost in a merge * `IRP_MJ_DIRECTORY_CONTROL` (#12870) * `FileFullDirectoryInformation` (#12908) * Improve `ClientDriveQueryDirectoryResponse.encode()` (#12912) * `IRP_MJ_QUERY_VOLUME_INFORMATION` (#13071) * Fix Shared Directory Request handling when feature is disabled (#13439) * IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_SET_INFORMATION (#13995) * Adds constants for sizing calculations (#14051) Co-authored-by: Łukasz Kozłowski <lukasz.kozlowski@goteleport.com> Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
This commit is contained in:
parent
ced6276c7b
commit
361ea8ef3f
103
Cargo.lock
generated
103
Cargo.lock
generated
|
@ -66,9 +66,9 @@ checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
|||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179"
|
||||
checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851"
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
|
@ -166,9 +166,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.8"
|
||||
version = "3.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
|
||||
checksum = "54635806b078b7925d6e36810b1755f2a4b5b4d57560432c1ecf60bcbe10602b"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
|
@ -250,9 +250,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "delog"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb73cae03ad02cd38353f93fe84b288daffcb6371212226e09b9a4c7fc93b03f"
|
||||
checksum = "e371811fb858c17e75e0316e7ebf8db0343b10d73038a3b9571006b0e7e5cc53"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
@ -378,13 +378,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
||||
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -398,15 +398,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.7.13"
|
||||
version = "0.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a08e755adbc0ad283725b29f4a4883deee15336f372d5f61fae59efec40f983"
|
||||
checksum = "065681e99f9ef7e0e813702a0326aedbcbbde7db5e55f097aedd1bf50b9dca43"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"hash32",
|
||||
|
@ -448,9 +448,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.2"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
@ -492,9 +492,9 @@ checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.57"
|
||||
version = "0.3.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397"
|
||||
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -713,9 +713,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
|||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.1.0"
|
||||
version = "6.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
|
@ -765,18 +765,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.39"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
|
||||
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.18"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -840,7 +840,7 @@ version = "0.6.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.6",
|
||||
"getrandom 0.2.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -878,7 +878,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rdp-rs"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/gravitational/rdp-rs?rev=6075679e7c9bd8e3c2136a87f097d05c7db3235f#6075679e7c9bd8e3c2136a87f097d05c7db3235f"
|
||||
source = "git+https://github.com/gravitational/rdp-rs?rev=004207e2edfbc6a57fd04daf6bcade93bcc3495e#004207e2edfbc6a57fd04daf6bcade93bcc3495e"
|
||||
dependencies = [
|
||||
"bufstream",
|
||||
"byteorder",
|
||||
|
@ -1100,9 +1100,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.8.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
|
@ -1161,9 +1161,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.96"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf"
|
||||
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1201,11 +1201,12 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
|||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -1226,9 +1227,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
|
@ -1257,7 +1258,7 @@ version = "1.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
|
||||
dependencies = [
|
||||
"getrandom 0.2.6",
|
||||
"getrandom 0.2.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1295,15 +1296,21 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
|
||||
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -1311,9 +1318,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
|
||||
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
|
@ -1326,9 +1333,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
|
||||
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -1336,9 +1343,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
|
||||
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1349,15 +1356,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
|
||||
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.57"
|
||||
version = "0.3.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283"
|
||||
checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
|
@ -20,7 +20,7 @@ num-traits = "0.2.15"
|
|||
rand = { version = "0.8.5", features = ["getrandom"] }
|
||||
rand_chacha = "0.3.1"
|
||||
rsa = "0.6.1"
|
||||
rdp-rs = { git = "https://github.com/gravitational/rdp-rs", rev = "6075679e7c9bd8e3c2136a87f097d05c7db3235f" }
|
||||
rdp-rs = { git = "https://github.com/gravitational/rdp-rs", rev = "004207e2edfbc6a57fd04daf6bcade93bcc3495e" }
|
||||
uuid = { version = "1.1.2", features = ["v4"] }
|
||||
utf16string = "0.2.0"
|
||||
|
||||
|
|
|
@ -412,11 +412,11 @@ func (c *Client) start() {
|
|||
defer C.free(unsafe.Pointer(path))
|
||||
if errCode := C.handle_tdp_sd_info_response(c.rustClient, C.CGOSharedDirectoryInfoResponse{
|
||||
completion_id: C.uint32_t(m.CompletionID),
|
||||
err_code: C.uint32_t(m.ErrCode),
|
||||
err_code: m.ErrCode,
|
||||
fso: C.CGOFileSystemObject{
|
||||
last_modified: C.uint64_t(m.Fso.LastModified),
|
||||
size: C.uint64_t(m.Fso.Size),
|
||||
file_type: C.uint32_t(m.Fso.FileType),
|
||||
file_type: m.Fso.FileType,
|
||||
path: path,
|
||||
},
|
||||
}); errCode != C.ErrCodeSuccess {
|
||||
|
@ -424,6 +424,91 @@ func (c *Client) start() {
|
|||
return
|
||||
}
|
||||
}
|
||||
case tdp.SharedDirectoryCreateResponse:
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if errCode := C.handle_tdp_sd_create_response(c.rustClient, C.CGOSharedDirectoryCreateResponse{
|
||||
completion_id: C.uint32_t(m.CompletionID),
|
||||
err_code: m.ErrCode,
|
||||
}); errCode != C.ErrCodeSuccess {
|
||||
c.cfg.Log.Errorf("SharedDirectoryCreateResponse failed: %v", errCode)
|
||||
return
|
||||
}
|
||||
}
|
||||
case tdp.SharedDirectoryDeleteResponse:
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if errCode := C.handle_tdp_sd_delete_response(c.rustClient, C.CGOSharedDirectoryDeleteResponse{
|
||||
completion_id: C.uint32_t(m.CompletionID),
|
||||
err_code: m.ErrCode,
|
||||
}); errCode != C.ErrCodeSuccess {
|
||||
c.cfg.Log.Errorf("SharedDirectoryDeleteResponse failed: %v", errCode)
|
||||
return
|
||||
}
|
||||
}
|
||||
case tdp.SharedDirectoryListResponse:
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
fsoList := make([]C.CGOFileSystemObject, 0, len(m.FsoList))
|
||||
|
||||
for _, fso := range m.FsoList {
|
||||
path := C.CString(fso.Path)
|
||||
defer C.free(unsafe.Pointer(path))
|
||||
|
||||
fsoList = append(fsoList, C.CGOFileSystemObject{
|
||||
last_modified: C.uint64_t(fso.LastModified),
|
||||
size: C.uint64_t(fso.Size),
|
||||
file_type: fso.FileType,
|
||||
path: path,
|
||||
})
|
||||
}
|
||||
|
||||
fsoListLen := len(fsoList)
|
||||
var cgoFsoList *C.CGOFileSystemObject
|
||||
|
||||
if fsoListLen > 0 {
|
||||
cgoFsoList = (*C.CGOFileSystemObject)(unsafe.Pointer(&fsoList[0]))
|
||||
} else {
|
||||
cgoFsoList = (*C.CGOFileSystemObject)(unsafe.Pointer(&fsoList))
|
||||
}
|
||||
|
||||
if errCode := C.handle_tdp_sd_list_response(c.rustClient, C.CGOSharedDirectoryListResponse{
|
||||
completion_id: C.uint32_t(m.CompletionID),
|
||||
err_code: m.ErrCode,
|
||||
fso_list_length: C.uint32_t(fsoListLen),
|
||||
fso_list: cgoFsoList,
|
||||
}); errCode != C.ErrCodeSuccess {
|
||||
c.cfg.Log.Errorf("SharedDirectoryListResponse failed: %v", errCode)
|
||||
return
|
||||
}
|
||||
}
|
||||
case tdp.SharedDirectoryReadResponse:
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
var readData *C.uint8_t
|
||||
if m.ReadDataLength > 0 {
|
||||
readData = (*C.uint8_t)(unsafe.Pointer(&m.ReadData[0]))
|
||||
} else {
|
||||
readData = (*C.uint8_t)(unsafe.Pointer(&m.ReadData))
|
||||
}
|
||||
|
||||
if errCode := C.handle_tdp_sd_read_response(c.rustClient, C.CGOSharedDirectoryReadResponse{
|
||||
completion_id: C.uint32_t(m.CompletionID),
|
||||
err_code: m.ErrCode,
|
||||
read_data_length: C.uint32_t(m.ReadDataLength),
|
||||
read_data: readData,
|
||||
}); errCode != C.ErrCodeSuccess {
|
||||
c.cfg.Log.Errorf("SharedDirectoryReadResponse failed: %v", errCode)
|
||||
return
|
||||
}
|
||||
}
|
||||
case tdp.SharedDirectoryWriteResponse:
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if errCode := C.handle_tdp_sd_write_response(c.rustClient, C.CGOSharedDirectoryWriteResponse{
|
||||
completion_id: C.uint32_t(m.CompletionID),
|
||||
err_code: m.ErrCode,
|
||||
bytes_written: C.uint32_t(m.BytesWritten),
|
||||
}); errCode != C.ErrCodeSuccess {
|
||||
c.cfg.Log.Errorf("SharedDirectoryWriteResponse failed: %v", errCode)
|
||||
return
|
||||
}
|
||||
}
|
||||
default:
|
||||
c.cfg.Log.Warningf("Skipping unimplemented TDP message type %T", msg)
|
||||
}
|
||||
|
@ -497,15 +582,18 @@ func tdp_sd_acknowledge(handle C.uintptr_t, ack *C.CGOSharedDirectoryAcknowledge
|
|||
})
|
||||
}
|
||||
|
||||
// sharedDirectoryAcknowledge acknowledges that a `Shared Directory Announce` TDP message was processed.
|
||||
// sharedDirectoryAcknowledge is sent by the TDP server to the client
|
||||
// to acknowledge that a SharedDirectoryAnnounce was received.
|
||||
func (c *Client) sharedDirectoryAcknowledge(ack tdp.SharedDirectoryAcknowledge) C.CGOErrCode {
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if err := c.cfg.Conn.OutputMessage(ack); err != nil {
|
||||
c.cfg.Log.Errorf("failed to send SharedDirectoryAcknowledge: %v", err)
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
return C.ErrCodeSuccess
|
||||
}
|
||||
return C.ErrCodeSuccess
|
||||
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
|
||||
//export tdp_sd_info_request
|
||||
|
@ -517,14 +605,139 @@ func tdp_sd_info_request(handle C.uintptr_t, req *C.CGOSharedDirectoryInfoReques
|
|||
})
|
||||
}
|
||||
|
||||
// sharedDirectoryInfoRequest is sent from the TDP server to the client
|
||||
// to request information about a file or directory at a given path.
|
||||
func (c *Client) sharedDirectoryInfoRequest(req tdp.SharedDirectoryInfoRequest) C.CGOErrCode {
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if err := c.cfg.Conn.OutputMessage(req); err != nil {
|
||||
c.cfg.Log.Errorf("failed to send SharedDirectoryAcknowledge: %v", err)
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
return C.ErrCodeSuccess
|
||||
}
|
||||
return C.ErrCodeSuccess
|
||||
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
|
||||
//export tdp_sd_create_request
|
||||
func tdp_sd_create_request(handle C.uintptr_t, req *C.CGOSharedDirectoryCreateRequest) C.CGOErrCode {
|
||||
return cgo.Handle(handle).Value().(*Client).sharedDirectoryCreateRequest(tdp.SharedDirectoryCreateRequest{
|
||||
CompletionID: uint32(req.completion_id),
|
||||
DirectoryID: uint32(req.directory_id),
|
||||
FileType: uint32(req.file_type),
|
||||
Path: C.GoString(req.path),
|
||||
})
|
||||
}
|
||||
|
||||
// sharedDirectoryCreateRequest is sent by the TDP server to
|
||||
// the client to request the creation of a new file or directory.
|
||||
func (c *Client) sharedDirectoryCreateRequest(req tdp.SharedDirectoryCreateRequest) C.CGOErrCode {
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if err := c.cfg.Conn.OutputMessage(req); err != nil {
|
||||
c.cfg.Log.Errorf("failed to send SharedDirectoryCreateRequest: %v", err)
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
return C.ErrCodeSuccess
|
||||
}
|
||||
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
|
||||
//export tdp_sd_delete_request
|
||||
func tdp_sd_delete_request(handle C.uintptr_t, req *C.CGOSharedDirectoryDeleteRequest) C.CGOErrCode {
|
||||
return cgo.Handle(handle).Value().(*Client).sharedDirectoryDeleteRequest(tdp.SharedDirectoryDeleteRequest{
|
||||
CompletionID: uint32(req.completion_id),
|
||||
DirectoryID: uint32(req.directory_id),
|
||||
Path: C.GoString(req.path),
|
||||
})
|
||||
}
|
||||
|
||||
// sharedDirectoryDeleteRequest is sent by the TDP server to the client
|
||||
// to request the deletion of a file or directory at path.
|
||||
func (c *Client) sharedDirectoryDeleteRequest(req tdp.SharedDirectoryDeleteRequest) C.CGOErrCode {
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if err := c.cfg.Conn.OutputMessage(req); err != nil {
|
||||
c.cfg.Log.Errorf("failed to send SharedDirectoryDeleteRequest: %v", err)
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
return C.ErrCodeSuccess
|
||||
}
|
||||
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
|
||||
//export tdp_sd_list_request
|
||||
func tdp_sd_list_request(handle C.uintptr_t, req *C.CGOSharedDirectoryListRequest) C.CGOErrCode {
|
||||
return cgo.Handle(handle).Value().(*Client).sharedDirectoryListRequest(tdp.SharedDirectoryListRequest{
|
||||
CompletionID: uint32(req.completion_id),
|
||||
DirectoryID: uint32(req.directory_id),
|
||||
Path: C.GoString(req.path),
|
||||
})
|
||||
}
|
||||
|
||||
// sharedDirectoryListRequest is sent by the TDP server to the client
|
||||
// to request the contents of a directory.
|
||||
func (c *Client) sharedDirectoryListRequest(req tdp.SharedDirectoryListRequest) C.CGOErrCode {
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if err := c.cfg.Conn.OutputMessage(req); err != nil {
|
||||
c.cfg.Log.Errorf("failed to send SharedDirectoryListRequest: %v", err)
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
return C.ErrCodeSuccess
|
||||
}
|
||||
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
|
||||
//export tdp_sd_read_request
|
||||
func tdp_sd_read_request(handle C.uintptr_t, req *C.CGOSharedDirectoryReadRequest) C.CGOErrCode {
|
||||
return cgo.Handle(handle).Value().(*Client).sharedDirectoryReadRequest(tdp.SharedDirectoryReadRequest{
|
||||
CompletionID: uint32(req.completion_id),
|
||||
DirectoryID: uint32(req.directory_id),
|
||||
Path: C.GoString(req.path),
|
||||
PathLength: uint32(req.path_length),
|
||||
Offset: uint64(req.offset),
|
||||
Length: uint32(req.length),
|
||||
})
|
||||
}
|
||||
|
||||
// SharedDirectoryReadRequest is sent by the TDP server to the client
|
||||
// to request the contents of a file.
|
||||
func (c *Client) sharedDirectoryReadRequest(req tdp.SharedDirectoryReadRequest) C.CGOErrCode {
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if err := c.cfg.Conn.OutputMessage(req); err != nil {
|
||||
c.cfg.Log.Errorf("failed to send SharedDirectoryReadRequest: %v", err)
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
return C.ErrCodeSuccess
|
||||
}
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
|
||||
//export tdp_sd_write_request
|
||||
func tdp_sd_write_request(handle C.uintptr_t, req *C.CGOSharedDirectoryWriteRequest) C.CGOErrCode {
|
||||
return cgo.Handle(handle).Value().(*Client).sharedDirectoryWriteRequest(tdp.SharedDirectoryWriteRequest{
|
||||
CompletionID: uint32(req.completion_id),
|
||||
DirectoryID: uint32(req.directory_id),
|
||||
Offset: uint64(req.offset),
|
||||
PathLength: uint32(req.path_length),
|
||||
Path: C.GoString(req.path),
|
||||
WriteDataLength: uint32(req.write_data_length),
|
||||
WriteData: C.GoBytes(unsafe.Pointer(req.write_data), C.int(req.write_data_length)),
|
||||
})
|
||||
}
|
||||
|
||||
// SharedDirectoryWriteRequest is sent by the TDP server to the client
|
||||
// to write to a file.
|
||||
func (c *Client) sharedDirectoryWriteRequest(req tdp.SharedDirectoryWriteRequest) C.CGOErrCode {
|
||||
if c.cfg.AllowDirectorySharing {
|
||||
if err := c.cfg.Conn.OutputMessage(req); err != nil {
|
||||
c.cfg.Log.Errorf("failed to send SharedDirectoryWriteRequest: %v", err)
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
return C.ErrCodeSuccess
|
||||
}
|
||||
return C.ErrCodeFailure
|
||||
}
|
||||
|
||||
// close closes the RDP client connection and
|
||||
|
|
|
@ -24,6 +24,7 @@ extern crate log;
|
|||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
|
||||
use errors::try_error;
|
||||
use libc::{fd_set, select, FD_SET};
|
||||
use rand::Rng;
|
||||
use rand::SeedableRng;
|
||||
|
@ -164,8 +165,8 @@ pub unsafe extern "C" fn connect_rdp(
|
|||
// Convert from C to Rust types.
|
||||
let addr = from_go_string(go_addr);
|
||||
let username = from_go_string(go_username);
|
||||
let cert_der = from_go_array(cert_der_len, cert_der);
|
||||
let key_der = from_go_array(key_der_len, key_der);
|
||||
let cert_der = from_go_array(cert_der, cert_der_len);
|
||||
let key_der = from_go_array(key_der, key_der_len);
|
||||
|
||||
connect_rdp_inner(
|
||||
go_ref,
|
||||
|
@ -288,22 +289,22 @@ fn connect_rdp_inner(
|
|||
"rdp-rs",
|
||||
);
|
||||
|
||||
let tdp_sd_acknowledge = Box::new(move |ack: SharedDirectoryAcknowledge| -> RdpResult<()> {
|
||||
debug!("sending: {:?}", ack);
|
||||
unsafe {
|
||||
if tdp_sd_acknowledge(go_ref, &mut CGOSharedDirectoryAcknowledge::from(ack))
|
||||
!= CGOErrCode::ErrCodeSuccess
|
||||
{
|
||||
return Err(RdpError::TryError(String::from(
|
||||
"call to tdp_sd_acknowledge failed",
|
||||
)));
|
||||
let tdp_sd_acknowledge = Box::new(
|
||||
move |mut ack: SharedDirectoryAcknowledge| -> RdpResult<()> {
|
||||
debug!("sending TDP SharedDirectoryAcknowledge: {:?}", ack);
|
||||
unsafe {
|
||||
if tdp_sd_acknowledge(go_ref, &mut ack) != CGOErrCode::ErrCodeSuccess {
|
||||
return Err(RdpError::TryError(String::from(
|
||||
"call to tdp_sd_acknowledge failed",
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let tdp_sd_info_request = Box::new(move |req: SharedDirectoryInfoRequest| -> RdpResult<()> {
|
||||
debug!("sending: {:?}", req);
|
||||
debug!("sending TDP SharedDirectoryInfoRequest: {:?}", req);
|
||||
// Create C compatible string from req.path
|
||||
match CString::new(req.path.clone()) {
|
||||
Ok(c_string) => {
|
||||
|
@ -334,15 +335,188 @@ fn connect_rdp_inner(
|
|||
}
|
||||
});
|
||||
|
||||
let tdp_sd_create_request =
|
||||
Box::new(move |req: SharedDirectoryCreateRequest| -> RdpResult<()> {
|
||||
debug!("sending TDP SharedDirectoryCreateRequest: {:?}", req);
|
||||
// Create C compatible string from req.path
|
||||
match CString::new(req.path.clone()) {
|
||||
Ok(c_string) => {
|
||||
unsafe {
|
||||
let err = tdp_sd_create_request(
|
||||
go_ref,
|
||||
&mut CGOSharedDirectoryCreateRequest {
|
||||
completion_id: req.completion_id,
|
||||
directory_id: req.directory_id,
|
||||
file_type: req.file_type,
|
||||
path: c_string.as_ptr(),
|
||||
},
|
||||
);
|
||||
if err != CGOErrCode::ErrCodeSuccess {
|
||||
return Err(RdpError::TryError(String::from(
|
||||
"call to tdp_sd_create_request failed",
|
||||
)));
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => {
|
||||
// TODO(isaiah): change TryError to TeleportError for a generic error caused by Teleport specific code.
|
||||
return Err(RdpError::TryError(format!(
|
||||
"path contained characters that couldn't be converted to a C string: {}",
|
||||
req.path
|
||||
)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let tdp_sd_delete_request =
|
||||
Box::new(move |req: SharedDirectoryDeleteRequest| -> RdpResult<()> {
|
||||
debug!("sending TDP SharedDirectoryDeleteRequest: {:?}", req);
|
||||
// Create C compatible string from req.path
|
||||
match CString::new(req.path.clone()) {
|
||||
Ok(c_string) => {
|
||||
unsafe {
|
||||
let err = tdp_sd_delete_request(
|
||||
go_ref,
|
||||
&mut CGOSharedDirectoryDeleteRequest {
|
||||
completion_id: req.completion_id,
|
||||
directory_id: req.directory_id,
|
||||
path: c_string.as_ptr(),
|
||||
},
|
||||
);
|
||||
if err != CGOErrCode::ErrCodeSuccess {
|
||||
return Err(RdpError::TryError(String::from(
|
||||
"call to tdp_sd_delete_request failed",
|
||||
)));
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => {
|
||||
// TODO(isaiah): change TryError to TeleportError for a generic error caused by Teleport specific code.
|
||||
return Err(RdpError::TryError(format!(
|
||||
"path contained characters that couldn't be converted to a C string: {}",
|
||||
req.path
|
||||
)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let tdp_sd_list_request = Box::new(move |req: SharedDirectoryListRequest| -> RdpResult<()> {
|
||||
debug!("sending TDP SharedDirectoryListRequest: {:?}", req);
|
||||
// Create C compatible string from req.path
|
||||
match CString::new(req.path.clone()) {
|
||||
Ok(c_string) => {
|
||||
unsafe {
|
||||
let err = tdp_sd_list_request(
|
||||
go_ref,
|
||||
&mut CGOSharedDirectoryListRequest {
|
||||
completion_id: req.completion_id,
|
||||
directory_id: req.directory_id,
|
||||
path: c_string.as_ptr(),
|
||||
},
|
||||
);
|
||||
if err != CGOErrCode::ErrCodeSuccess {
|
||||
return Err(RdpError::TryError(String::from(
|
||||
"call to tdp_sd_list_request failed",
|
||||
)));
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => {
|
||||
// TODO(isaiah): change TryError to TeleportError for a generic error caused by Teleport specific code.
|
||||
return Err(RdpError::TryError(format!(
|
||||
"path contained characters that couldn't be converted to a C string: {}",
|
||||
req.path
|
||||
)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let tdp_sd_read_request = Box::new(move |req: SharedDirectoryReadRequest| -> RdpResult<()> {
|
||||
debug!("sending: {:?}", req);
|
||||
match CString::new(req.path.clone()) {
|
||||
Ok(c_string) => {
|
||||
unsafe {
|
||||
let err = tdp_sd_read_request(
|
||||
go_ref,
|
||||
&mut CGOSharedDirectoryReadRequest {
|
||||
completion_id: req.completion_id,
|
||||
directory_id: req.directory_id,
|
||||
path: c_string.as_ptr(),
|
||||
path_length: req.path.len() as u32,
|
||||
offset: req.offset,
|
||||
length: req.length,
|
||||
},
|
||||
);
|
||||
|
||||
if err != CGOErrCode::ErrCodeSuccess {
|
||||
return Err(RdpError::TryError(String::from(
|
||||
"call to tdp_sd_read_request failed",
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(RdpError::TryError(format!(
|
||||
"path contained characters that couldn't be converted to a C string: {}",
|
||||
req.path
|
||||
)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let tdp_sd_write_request = Box::new(move |req: SharedDirectoryWriteRequest| -> RdpResult<()> {
|
||||
debug!("sending: {:?}", req);
|
||||
match CString::new(req.path.clone()) {
|
||||
Ok(c_string) => {
|
||||
unsafe {
|
||||
let err = tdp_sd_write_request(
|
||||
go_ref,
|
||||
&mut CGOSharedDirectoryWriteRequest {
|
||||
completion_id: req.completion_id,
|
||||
directory_id: req.directory_id,
|
||||
offset: req.offset,
|
||||
path: c_string.as_ptr(),
|
||||
path_length: req.path.len() as u32,
|
||||
write_data_length: req.write_data.len() as u32,
|
||||
write_data: req.write_data.as_ptr() as *mut u8,
|
||||
},
|
||||
);
|
||||
|
||||
if err != CGOErrCode::ErrCodeSuccess {
|
||||
return Err(RdpError::TryError(String::from(
|
||||
"call to tdp_sd_write_failed",
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(RdpError::TryError(format!(
|
||||
"path contained characters that couldn't be converted to a C string: {}",
|
||||
req.path
|
||||
)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Client for the "rdpdr" channel - smartcard emulation and drive redirection.
|
||||
let rdpdr = rdpdr::Client::new(
|
||||
params.cert_der,
|
||||
params.key_der,
|
||||
let rdpdr = rdpdr::Client::new(rdpdr::Config {
|
||||
cert_der: params.cert_der,
|
||||
key_der: params.key_der,
|
||||
pin,
|
||||
params.allow_directory_sharing,
|
||||
allow_directory_sharing: params.allow_directory_sharing,
|
||||
tdp_sd_acknowledge,
|
||||
tdp_sd_info_request,
|
||||
);
|
||||
tdp_sd_create_request,
|
||||
tdp_sd_delete_request,
|
||||
tdp_sd_list_request,
|
||||
tdp_sd_read_request,
|
||||
tdp_sd_write_request,
|
||||
});
|
||||
|
||||
// Client for the "cliprdr" channel - clipboard sharing.
|
||||
let cliprdr = if params.allow_clipboard {
|
||||
|
@ -443,6 +617,41 @@ impl<S: Read + Write> RdpClient<S> {
|
|||
self.rdpdr.handle_tdp_sd_info_response(res, &mut self.mcs)
|
||||
}
|
||||
|
||||
pub fn handle_tdp_sd_create_response(
|
||||
&mut self,
|
||||
res: SharedDirectoryCreateResponse,
|
||||
) -> RdpResult<()> {
|
||||
self.rdpdr.handle_tdp_sd_create_response(res, &mut self.mcs)
|
||||
}
|
||||
|
||||
pub fn handle_tdp_sd_delete_response(
|
||||
&mut self,
|
||||
res: SharedDirectoryDeleteResponse,
|
||||
) -> RdpResult<()> {
|
||||
self.rdpdr.handle_tdp_sd_delete_response(res, &mut self.mcs)
|
||||
}
|
||||
|
||||
pub fn handle_tdp_sd_list_response(
|
||||
&mut self,
|
||||
res: SharedDirectoryListResponse,
|
||||
) -> RdpResult<()> {
|
||||
self.rdpdr.handle_tdp_sd_list_response(res, &mut self.mcs)
|
||||
}
|
||||
|
||||
pub fn handle_tdp_sd_read_response(
|
||||
&mut self,
|
||||
res: SharedDirectoryReadResponse,
|
||||
) -> RdpResult<()> {
|
||||
self.rdpdr.handle_tdp_sd_read_response(res, &mut self.mcs)
|
||||
}
|
||||
|
||||
pub fn handle_tdp_sd_write_response(
|
||||
&mut self,
|
||||
res: SharedDirectoryWriteResponse,
|
||||
) -> RdpResult<()> {
|
||||
self.rdpdr.handle_tdp_sd_write_response(res, &mut self.mcs)
|
||||
}
|
||||
|
||||
pub fn shutdown(&mut self) -> RdpResult<()> {
|
||||
self.mcs.shutdown()
|
||||
}
|
||||
|
@ -527,7 +736,11 @@ fn wait_for_fd(fd: usize) -> bool {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `client_ptr` must be a valid pointer to a Client.
|
||||
/// client_ptr MUST be a valid pointer.
|
||||
/// (validity defined by https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.as_ref-1)
|
||||
///
|
||||
/// data MUST be a valid pointer.
|
||||
/// (validity defined by the validity of data in https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html)
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn update_clipboard(
|
||||
client_ptr: *mut Client,
|
||||
|
@ -540,7 +753,7 @@ pub unsafe extern "C" fn update_clipboard(
|
|||
return cgo_error;
|
||||
}
|
||||
};
|
||||
let data = from_go_array(len, data);
|
||||
let data = from_go_array(data, len);
|
||||
let mut lock = client.rdp_client.lock().unwrap();
|
||||
|
||||
match lock.cliprdr {
|
||||
|
@ -568,14 +781,26 @@ pub unsafe extern "C" fn update_clipboard(
|
|||
/// handle_tdp_sd_announce announces a new drive that's ready to be
|
||||
/// redirected over RDP.
|
||||
///
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that sd_announce.name points to a valid buffer.
|
||||
/// client_ptr MUST be a valid pointer.
|
||||
/// (validity defined by https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.as_ref-1)
|
||||
///
|
||||
/// sd_announce.name MUST be a non-null pointer to a C-style null terminated string.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn handle_tdp_sd_announce(
|
||||
client_ptr: *mut Client,
|
||||
sd_announce: CGOSharedDirectoryAnnounce,
|
||||
) -> CGOErrCode {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
|
||||
let sd_announce = SharedDirectoryAnnounce::from(sd_announce);
|
||||
|
||||
let client = match Client::from_ptr(client_ptr) {
|
||||
Ok(client) => client,
|
||||
Err(cgo_error) => {
|
||||
|
@ -583,9 +808,8 @@ pub unsafe extern "C" fn handle_tdp_sd_announce(
|
|||
}
|
||||
};
|
||||
|
||||
let drive_name = from_go_string(sd_announce.name);
|
||||
let new_drive =
|
||||
rdpdr::ClientDeviceListAnnounce::new_drive(sd_announce.directory_id, drive_name);
|
||||
rdpdr::ClientDeviceListAnnounce::new_drive(sd_announce.directory_id, sd_announce.name);
|
||||
|
||||
let mut rdp_client = client.rdp_client.lock().unwrap();
|
||||
match rdp_client.write_client_device_list_announce(new_drive) {
|
||||
|
@ -602,11 +826,165 @@ pub unsafe extern "C" fn handle_tdp_sd_announce(
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that res.fso.path points to a valid buffer.
|
||||
/// client_ptr MUST be a valid pointer.
|
||||
/// (validity defined by https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.as_ref-1)
|
||||
///
|
||||
/// res.fso.path MUST be a non-null pointer to a C-style null terminated string.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn handle_tdp_sd_info_response(
|
||||
client_ptr: *mut Client,
|
||||
res: CGOSharedDirectoryInfoResponse,
|
||||
) -> CGOErrCode {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
|
||||
let res = SharedDirectoryInfoResponse::from(res);
|
||||
|
||||
let client = match Client::from_ptr(client_ptr) {
|
||||
Ok(client) => client,
|
||||
Err(cgo_error) => {
|
||||
return cgo_error;
|
||||
}
|
||||
};
|
||||
|
||||
let mut rdp_client = client.rdp_client.lock().unwrap();
|
||||
match rdp_client.handle_tdp_sd_info_response(res) {
|
||||
Ok(()) => CGOErrCode::ErrCodeSuccess,
|
||||
Err(e) => {
|
||||
error!("failed to handle Shared Directory Info Response: {:?}", e);
|
||||
CGOErrCode::ErrCodeFailure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// handle_tdp_sd_create_response handles a TDP Shared Directory Create Response
|
||||
/// message
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// client_ptr MUST be a valid pointer.
|
||||
/// (validity defined by https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.as_ref-1)
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn handle_tdp_sd_create_response(
|
||||
client_ptr: *mut Client,
|
||||
res: CGOSharedDirectoryCreateResponse,
|
||||
) -> CGOErrCode {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
|
||||
let res: SharedDirectoryCreateResponse = res;
|
||||
|
||||
let client = match Client::from_ptr(client_ptr) {
|
||||
Ok(client) => client,
|
||||
Err(cgo_error) => {
|
||||
return cgo_error;
|
||||
}
|
||||
};
|
||||
|
||||
let mut rdp_client = client.rdp_client.lock().unwrap();
|
||||
match rdp_client.handle_tdp_sd_create_response(res) {
|
||||
Ok(()) => CGOErrCode::ErrCodeSuccess,
|
||||
Err(e) => {
|
||||
error!("failed to handle Shared Directory Create Response: {:?}", e);
|
||||
CGOErrCode::ErrCodeFailure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// handle_tdp_sd_delete_response handles a TDP Shared Directory Delete Response
|
||||
/// message
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// client_ptr MUST be a valid pointer.
|
||||
/// (validity defined by https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.as_ref-1)
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn handle_tdp_sd_delete_response(
|
||||
client_ptr: *mut Client,
|
||||
res: CGOSharedDirectoryDeleteResponse,
|
||||
) -> CGOErrCode {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
|
||||
let res: SharedDirectoryDeleteResponse = res;
|
||||
|
||||
let client = match Client::from_ptr(client_ptr) {
|
||||
Ok(client) => client,
|
||||
Err(cgo_error) => {
|
||||
return cgo_error;
|
||||
}
|
||||
};
|
||||
|
||||
let mut rdp_client = client.rdp_client.lock().unwrap();
|
||||
match rdp_client.handle_tdp_sd_delete_response(res) {
|
||||
Ok(()) => CGOErrCode::ErrCodeSuccess,
|
||||
Err(e) => {
|
||||
error!("failed to handle Shared Directory Create Response: {:?}", e);
|
||||
CGOErrCode::ErrCodeFailure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// handle_tdp_sd_list_response handles a TDP Shared Directory List Response message.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// client_ptr MUST be a valid pointer.
|
||||
/// (validity defined by https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.as_ref-1)
|
||||
///
|
||||
/// res.fso_list MUST be a valid pointer
|
||||
/// (validity defined by the validity of data in https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html)
|
||||
///
|
||||
/// each res.fso_list[i].path MUST be a non-null pointer to a C-style null terminated string.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn handle_tdp_sd_list_response(
|
||||
client_ptr: *mut Client,
|
||||
res: CGOSharedDirectoryListResponse,
|
||||
) -> CGOErrCode {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
|
||||
let res = SharedDirectoryListResponse::from(res);
|
||||
|
||||
let client = match Client::from_ptr(client_ptr) {
|
||||
Ok(client) => client,
|
||||
Err(cgo_error) => {
|
||||
return cgo_error;
|
||||
}
|
||||
};
|
||||
|
||||
let mut rdp_client = client.rdp_client.lock().unwrap();
|
||||
match rdp_client.handle_tdp_sd_list_response(res) {
|
||||
Ok(()) => CGOErrCode::ErrCodeSuccess,
|
||||
Err(e) => {
|
||||
error!("failed to handle Shared Directory List Response: {:?}", e);
|
||||
CGOErrCode::ErrCodeFailure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// handle_tdp_sd_read_response handles a TDP Shared Directory Read Response
|
||||
/// message
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// client_ptr must be a valid pointer
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn handle_tdp_sd_read_response(
|
||||
client_ptr: *mut Client,
|
||||
res: CGOSharedDirectoryReadResponse,
|
||||
) -> CGOErrCode {
|
||||
let client = match Client::from_ptr(client_ptr) {
|
||||
Ok(client) => client,
|
||||
|
@ -616,10 +994,39 @@ pub unsafe extern "C" fn handle_tdp_sd_info_response(
|
|||
};
|
||||
|
||||
let mut rdp_client = client.rdp_client.lock().unwrap();
|
||||
match rdp_client.handle_tdp_sd_info_response(SharedDirectoryInfoResponse::from(res)) {
|
||||
match rdp_client.handle_tdp_sd_read_response(SharedDirectoryReadResponse::from(res)) {
|
||||
Ok(()) => CGOErrCode::ErrCodeSuccess,
|
||||
Err(e) => {
|
||||
error!("failed to handle Shared Directory Info Response: {:?}", e);
|
||||
error!("failed to handle Shared Directory Read Response: {:?}", e);
|
||||
CGOErrCode::ErrCodeFailure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// handle_tdp_sd_write_response handles a TDP Shared Directory Write Response
|
||||
/// message
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// client_ptr must be a valid pointer
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn handle_tdp_sd_write_response(
|
||||
client_ptr: *mut Client,
|
||||
res: CGOSharedDirectoryWriteResponse,
|
||||
) -> CGOErrCode {
|
||||
let client = match Client::from_ptr(client_ptr) {
|
||||
Ok(client) => client,
|
||||
Err(cgo_error) => {
|
||||
return cgo_error;
|
||||
}
|
||||
};
|
||||
|
||||
let mut rdp_client = client.rdp_client.lock().unwrap();
|
||||
|
||||
match rdp_client.handle_tdp_sd_write_response(res) {
|
||||
Ok(()) => CGOErrCode::ErrCodeSuccess,
|
||||
Err(e) => {
|
||||
error!("failed to handle Shared Directory Write Response: {:?}", e);
|
||||
CGOErrCode::ErrCodeFailure
|
||||
}
|
||||
}
|
||||
|
@ -735,6 +1142,11 @@ pub enum CGOPointerWheel {
|
|||
|
||||
impl From<CGOMousePointerEvent> for PointerEvent {
|
||||
fn from(p: CGOMousePointerEvent) -> PointerEvent {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
PointerEvent {
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
|
@ -757,7 +1169,8 @@ impl From<CGOMousePointerEvent> for PointerEvent {
|
|||
|
||||
/// # Safety
|
||||
///
|
||||
/// client_ptr must be a valid pointer to a Client.
|
||||
/// client_ptr MUST be a valid pointer.
|
||||
/// (validity defined by https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.as_ref-1)
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn write_rdp_pointer(
|
||||
client_ptr: *mut Client,
|
||||
|
@ -797,6 +1210,11 @@ pub struct CGOKeyboardEvent {
|
|||
|
||||
impl From<CGOKeyboardEvent> for KeyboardEvent {
|
||||
fn from(k: CGOKeyboardEvent) -> KeyboardEvent {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
KeyboardEvent {
|
||||
code: k.code,
|
||||
down: k.down,
|
||||
|
@ -806,7 +1224,8 @@ impl From<CGOKeyboardEvent> for KeyboardEvent {
|
|||
|
||||
/// # Safety
|
||||
///
|
||||
/// client_ptr must be a valid pointer to a Client.
|
||||
/// client_ptr MUST be a valid pointer.
|
||||
/// (validity defined by https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.as_ref-1)
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn write_rdp_keyboard(
|
||||
client_ptr: *mut Client,
|
||||
|
@ -860,7 +1279,8 @@ pub unsafe extern "C" fn close_rdp(client_ptr: *mut Client) -> CGOErrCode {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// client_ptr must be a valid pointer to a Client.
|
||||
/// client_ptr MUST be a valid pointer.
|
||||
/// (validity defined by https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.as_ref-1)
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn free_rdp(client_ptr: *mut Client) {
|
||||
drop(Client::from_raw(client_ptr))
|
||||
|
@ -872,14 +1292,24 @@ pub unsafe extern "C" fn free_rdp(client_ptr: *mut Client) {
|
|||
/// s is cloned here, and the caller is responsible for
|
||||
/// ensuring its memory is freed.
|
||||
unsafe fn from_go_string(s: *const c_char) -> String {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
CStr::from_ptr(s).to_string_lossy().into_owned()
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// ptr must be a valid buffer of len bytes.
|
||||
unsafe fn from_go_array(len: u32, ptr: *mut u8) -> Vec<u8> {
|
||||
slice::from_raw_parts(ptr, len as usize).to_vec()
|
||||
/// See https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html
|
||||
unsafe fn from_go_array<T: Clone>(data: *mut T, len: u32) -> Vec<T> {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
slice::from_raw_parts(data, len as usize).to_vec()
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -895,29 +1325,42 @@ pub struct CGOSharedDirectoryAnnounce {
|
|||
pub name: *const c_char,
|
||||
}
|
||||
|
||||
/// SharedDirectoryAcknowledge is a CGO-compatible version of
|
||||
/// the TDP Shared Directory Knowledge message that we pass back to Go.
|
||||
#[derive(Debug)]
|
||||
pub struct SharedDirectoryAcknowledge {
|
||||
pub err_code: u32,
|
||||
pub directory_id: u32,
|
||||
/// SharedDirectoryAnnounce is sent by the TDP client to the server
|
||||
/// to announce a new directory to be shared over TDP.
|
||||
pub struct SharedDirectoryAnnounce {
|
||||
directory_id: u32,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CGOSharedDirectoryAcknowledge {
|
||||
pub err_code: u32,
|
||||
pub directory_id: u32,
|
||||
}
|
||||
|
||||
impl From<SharedDirectoryAcknowledge> for CGOSharedDirectoryAcknowledge {
|
||||
fn from(ack: SharedDirectoryAcknowledge) -> CGOSharedDirectoryAcknowledge {
|
||||
CGOSharedDirectoryAcknowledge {
|
||||
err_code: ack.err_code,
|
||||
directory_id: ack.directory_id,
|
||||
impl From<CGOSharedDirectoryAnnounce> for SharedDirectoryAnnounce {
|
||||
fn from(cgo: CGOSharedDirectoryAnnounce) -> SharedDirectoryAnnounce {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
unsafe {
|
||||
SharedDirectoryAnnounce {
|
||||
directory_id: cgo.directory_id,
|
||||
name: from_go_string(cgo.name),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SharedDirectoryAcknowledge is sent by the TDP server to the client
|
||||
/// to acknowledge that a SharedDirectoryAnnounce was received.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct SharedDirectoryAcknowledge {
|
||||
pub err_code: TdpErrCode,
|
||||
pub directory_id: u32,
|
||||
}
|
||||
|
||||
pub type CGOSharedDirectoryAcknowledge = SharedDirectoryAcknowledge;
|
||||
|
||||
/// SharedDirectoryInfoRequest is sent from the TDP server to the client
|
||||
/// to request information about a file or directory at a given path.
|
||||
#[derive(Debug)]
|
||||
pub struct SharedDirectoryInfoRequest {
|
||||
completion_id: u32,
|
||||
|
@ -942,23 +1385,29 @@ impl From<ServerCreateDriveRequest> for SharedDirectoryInfoRequest {
|
|||
}
|
||||
}
|
||||
|
||||
/// SharedDirectoryInfoResponse is sent by the TDP client to the server
|
||||
/// in response to a `Shared Directory Info Request`.
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct SharedDirectoryInfoResponse {
|
||||
completion_id: u32,
|
||||
err_code: u32,
|
||||
err_code: TdpErrCode,
|
||||
fso: FileSystemObject,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CGOSharedDirectoryInfoResponse {
|
||||
pub completion_id: u32,
|
||||
pub err_code: u32,
|
||||
pub err_code: TdpErrCode,
|
||||
pub fso: CGOFileSystemObject,
|
||||
}
|
||||
|
||||
impl From<CGOSharedDirectoryInfoResponse> for SharedDirectoryInfoResponse {
|
||||
fn from(cgo_res: CGOSharedDirectoryInfoResponse) -> SharedDirectoryInfoResponse {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
SharedDirectoryInfoResponse {
|
||||
completion_id: cgo_res.completion_id,
|
||||
err_code: cgo_res.err_code,
|
||||
|
@ -967,25 +1416,45 @@ impl From<CGOSharedDirectoryInfoResponse> for SharedDirectoryInfoResponse {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
/// FileSystemObject is a TDP structure containing the metadata
|
||||
/// of a file or directory.
|
||||
pub struct FileSystemObject {
|
||||
last_modified: u64,
|
||||
size: u64,
|
||||
file_type: u32, // TODO(isaiah): make an enum
|
||||
file_type: FileType,
|
||||
path: String,
|
||||
}
|
||||
|
||||
impl FileSystemObject {
|
||||
fn name(&self) -> RdpResult<String> {
|
||||
if let Some(name) = self.path.split('/').last() {
|
||||
Ok(name.to_string())
|
||||
} else {
|
||||
Err(try_error(&format!(
|
||||
"failed to extract name from path: {:?}",
|
||||
self.path
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct CGOFileSystemObject {
|
||||
pub last_modified: u64,
|
||||
pub size: u64,
|
||||
pub file_type: u32, // TODO(isaiah): make an enum
|
||||
pub file_type: FileType,
|
||||
pub path: *const c_char,
|
||||
}
|
||||
|
||||
impl From<CGOFileSystemObject> for FileSystemObject {
|
||||
fn from(cgo_fso: CGOFileSystemObject) -> FileSystemObject {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
unsafe {
|
||||
FileSystemObject {
|
||||
last_modified: cgo_fso.last_modified,
|
||||
|
@ -997,6 +1466,194 @@ impl From<CGOFileSystemObject> for FileSystemObject {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum FileType {
|
||||
File = 0,
|
||||
Directory = 1,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum TdpErrCode {
|
||||
/// nil (no error, operation succeeded)
|
||||
Nil = 0,
|
||||
/// operation failed
|
||||
Failed = 1,
|
||||
/// resource does not exist
|
||||
DoesNotExist = 2,
|
||||
/// resource already exists
|
||||
AlreadyExists = 3,
|
||||
}
|
||||
|
||||
/// SharedDirectoryWriteRequest is sent by the TDP server to the client
|
||||
/// to write to a file.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SharedDirectoryWriteRequest {
|
||||
completion_id: u32,
|
||||
directory_id: u32,
|
||||
offset: u64,
|
||||
path: String,
|
||||
write_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CGOSharedDirectoryWriteRequest {
|
||||
pub completion_id: u32,
|
||||
pub directory_id: u32,
|
||||
pub offset: u64,
|
||||
pub path_length: u32,
|
||||
pub path: *const c_char,
|
||||
pub write_data_length: u32,
|
||||
pub write_data: *mut u8,
|
||||
}
|
||||
|
||||
/// SharedDirectoryReadRequest is sent by the TDP server to the client
|
||||
/// to request the contents of a file.
|
||||
#[derive(Debug)]
|
||||
pub struct SharedDirectoryReadRequest {
|
||||
completion_id: u32,
|
||||
directory_id: u32,
|
||||
path: String,
|
||||
offset: u64,
|
||||
length: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CGOSharedDirectoryReadRequest {
|
||||
pub completion_id: u32,
|
||||
pub directory_id: u32,
|
||||
pub path_length: u32,
|
||||
pub path: *const c_char,
|
||||
pub offset: u64,
|
||||
pub length: u32,
|
||||
}
|
||||
|
||||
/// SharedDirectoryReadResponse is sent by the TDP client to the server
|
||||
/// with the data as requested by a SharedDirectoryReadRequest.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct SharedDirectoryReadResponse {
|
||||
pub completion_id: u32,
|
||||
pub err_code: TdpErrCode,
|
||||
pub read_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl From<CGOSharedDirectoryReadResponse> for SharedDirectoryReadResponse {
|
||||
fn from(cgo_response: CGOSharedDirectoryReadResponse) -> SharedDirectoryReadResponse {
|
||||
unsafe {
|
||||
SharedDirectoryReadResponse {
|
||||
completion_id: cgo_response.completion_id,
|
||||
err_code: cgo_response.err_code,
|
||||
read_data: from_go_array(cgo_response.read_data, cgo_response.read_data_length),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CGOSharedDirectoryReadResponse {
|
||||
pub completion_id: u32,
|
||||
pub err_code: TdpErrCode,
|
||||
pub read_data_length: u32,
|
||||
pub read_data: *mut u8,
|
||||
}
|
||||
|
||||
/// SharedDirectoryWriteResponse is sent by the TDP client to the server
|
||||
/// to acknowledge the completion of a SharedDirectoryWriteRequest.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct SharedDirectoryWriteResponse {
|
||||
pub completion_id: u32,
|
||||
pub err_code: TdpErrCode,
|
||||
pub bytes_written: u32,
|
||||
}
|
||||
|
||||
pub type CGOSharedDirectoryWriteResponse = SharedDirectoryWriteResponse;
|
||||
|
||||
/// SharedDirectoryCreateRequest is sent by the TDP server to
|
||||
/// the client to request the creation of a new file or directory.
|
||||
#[derive(Debug)]
|
||||
pub struct SharedDirectoryCreateRequest {
|
||||
completion_id: u32,
|
||||
directory_id: u32,
|
||||
file_type: FileType,
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CGOSharedDirectoryCreateRequest {
|
||||
pub completion_id: u32,
|
||||
pub directory_id: u32,
|
||||
pub file_type: FileType,
|
||||
pub path: *const c_char,
|
||||
}
|
||||
|
||||
/// SharedDirectoryCreateResponse is sent by the TDP client to the server
|
||||
/// to acknowledge a SharedDirectoryCreateRequest was received and executed.
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct SharedDirectoryCreateResponse {
|
||||
pub completion_id: u32,
|
||||
pub err_code: TdpErrCode,
|
||||
}
|
||||
|
||||
/// SharedDirectoryListResponse is sent by the TDP client to the server
|
||||
/// in response to a SharedDirectoryInfoRequest.
|
||||
#[derive(Debug)]
|
||||
pub struct SharedDirectoryListResponse {
|
||||
completion_id: u32,
|
||||
err_code: TdpErrCode,
|
||||
fso_list: Vec<FileSystemObject>,
|
||||
}
|
||||
|
||||
impl From<CGOSharedDirectoryListResponse> for SharedDirectoryListResponse {
|
||||
fn from(cgo: CGOSharedDirectoryListResponse) -> SharedDirectoryListResponse {
|
||||
// # Safety
|
||||
//
|
||||
// This function MUST NOT hang on to any of the pointers passed in to it after it returns.
|
||||
// In other words, all pointer data that needs to persist after this function returns MUST
|
||||
// be copied into Rust-owned memory.
|
||||
unsafe {
|
||||
let cgo_fso_list = from_go_array(cgo.fso_list, cgo.fso_list_length);
|
||||
let mut fso_list = vec![];
|
||||
for cgo_fso in cgo_fso_list.into_iter() {
|
||||
fso_list.push(FileSystemObject::from(cgo_fso));
|
||||
}
|
||||
|
||||
SharedDirectoryListResponse {
|
||||
completion_id: cgo.completion_id,
|
||||
err_code: cgo.err_code,
|
||||
fso_list,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CGOSharedDirectoryListResponse {
|
||||
completion_id: u32,
|
||||
err_code: TdpErrCode,
|
||||
fso_list_length: u32,
|
||||
fso_list: *mut CGOFileSystemObject,
|
||||
}
|
||||
|
||||
pub type CGOSharedDirectoryCreateResponse = SharedDirectoryCreateResponse;
|
||||
/// SharedDirectoryDeleteRequest is sent by the TDP server to the client
|
||||
/// to request the deletion of a file or directory at path.
|
||||
pub type SharedDirectoryDeleteRequest = SharedDirectoryInfoRequest;
|
||||
pub type CGOSharedDirectoryDeleteRequest = CGOSharedDirectoryInfoRequest;
|
||||
/// SharedDirectoryDeleteResponse is sent by the TDP client to the server
|
||||
/// to acknowledge a SharedDirectoryDeleteRequest was received and executed.
|
||||
pub type SharedDirectoryDeleteResponse = SharedDirectoryCreateResponse;
|
||||
pub type CGOSharedDirectoryDeleteResponse = SharedDirectoryCreateResponse;
|
||||
/// SharedDirectoryListRequest is sent by the TDP server to the client
|
||||
/// to request the contents of a directory.
|
||||
pub type SharedDirectoryListRequest = SharedDirectoryInfoRequest;
|
||||
pub type CGOSharedDirectoryListRequest = CGOSharedDirectoryInfoRequest;
|
||||
|
||||
// These functions are defined on the Go side. Look for functions with '//export funcname'
|
||||
// comments.
|
||||
extern "C" {
|
||||
|
@ -1009,6 +1666,26 @@ extern "C" {
|
|||
client_ref: usize,
|
||||
req: *mut CGOSharedDirectoryInfoRequest,
|
||||
) -> CGOErrCode;
|
||||
fn tdp_sd_create_request(
|
||||
client_ref: usize,
|
||||
req: *mut CGOSharedDirectoryCreateRequest,
|
||||
) -> CGOErrCode;
|
||||
fn tdp_sd_delete_request(
|
||||
client_ref: usize,
|
||||
req: *mut CGOSharedDirectoryDeleteRequest,
|
||||
) -> CGOErrCode;
|
||||
fn tdp_sd_list_request(
|
||||
client_ref: usize,
|
||||
req: *mut CGOSharedDirectoryListRequest,
|
||||
) -> CGOErrCode;
|
||||
fn tdp_sd_read_request(
|
||||
client_ref: usize,
|
||||
req: *mut CGOSharedDirectoryReadRequest,
|
||||
) -> CGOErrCode;
|
||||
fn tdp_sd_write_request(
|
||||
client_ref: usize,
|
||||
req: *mut CGOSharedDirectoryWriteRequest,
|
||||
) -> CGOErrCode;
|
||||
}
|
||||
|
||||
/// Payload is a generic type used to represent raw incoming RDP messages for parsing.
|
||||
|
|
|
@ -12,10 +12,16 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::flags;
|
||||
use super::Boolean;
|
||||
|
||||
pub const CHANNEL_NAME: &str = "rdpdr";
|
||||
|
||||
// Each redirected device requires a unique ID. We only share
|
||||
// one permanent smartcard device, so we can give it hardcoded ID 1.
|
||||
pub const DIRECTORY_SHARE_CLIENT_NAME: &str = "teleport";
|
||||
|
||||
// Each redirected device requires a unique ID.
|
||||
pub const SCARD_DEVICE_ID: u32 = 1;
|
||||
|
||||
pub const VERSION_MAJOR: u16 = 0x0001;
|
||||
|
@ -100,7 +106,7 @@ pub enum MinorFunction {
|
|||
/// Windows defines an absolutely massive list of potential NTSTATUS values.
|
||||
/// This enum includes the basic ones we support for communicating with the windows machine.
|
||||
/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
|
||||
#[derive(ToPrimitive, Debug)]
|
||||
#[derive(ToPrimitive, Debug, PartialEq)]
|
||||
#[repr(u32)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(dead_code)]
|
||||
|
@ -109,6 +115,11 @@ pub enum NTSTATUS {
|
|||
STATUS_UNSUCCESSFUL = 0xC0000001,
|
||||
STATUS_NOT_IMPLEMENTED = 0xC0000002,
|
||||
STATUS_NO_MORE_FILES = 0x80000006,
|
||||
STATUS_OBJECT_NAME_COLLISION = 0xC0000035,
|
||||
STATUS_ACCESS_DENIED = 0xC0000022,
|
||||
STATUS_NOT_A_DIRECTORY = 0xC0000103,
|
||||
STATUS_NO_SUCH_FILE = 0xC000000F,
|
||||
STATUS_NOT_SUPPORTED = 0xC00000BB,
|
||||
}
|
||||
|
||||
/// 2.4 File Information Classes [MS-FSCC]
|
||||
|
@ -116,7 +127,7 @@ pub enum NTSTATUS {
|
|||
#[derive(FromPrimitive, Debug, PartialEq)]
|
||||
#[repr(u32)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum FsInformationClassLevel {
|
||||
pub enum FileInformationClassLevel {
|
||||
FileAccessInformation = 8,
|
||||
FileAlignmentInformation = 17,
|
||||
FileAllInformation = 18,
|
||||
|
@ -165,3 +176,33 @@ pub enum FsInformationClassLevel {
|
|||
FileTrackingInformation = 36,
|
||||
FileValidDataLengthInformation = 39,
|
||||
}
|
||||
|
||||
/// 2.5 File System Information Classes [MS-FSCC]
|
||||
/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ee12042a-9352-46e3-9f67-c094b75fe6c3
|
||||
#[derive(FromPrimitive, Debug, PartialEq)]
|
||||
#[repr(u32)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum FileSystemInformationClassLevel {
|
||||
FileFsVolumeInformation = 1,
|
||||
FileFsLabelInformation = 2,
|
||||
FileFsSizeInformation = 3,
|
||||
FileFsDeviceInformation = 4,
|
||||
FileFsAttributeInformation = 5,
|
||||
FileFsControlInformation = 6,
|
||||
FileFsFullSizeInformation = 7,
|
||||
FileFsObjectIdInformation = 8,
|
||||
FileFsDriverPathInformation = 9,
|
||||
FileFsVolumeFlagsInformation = 10,
|
||||
FileFsSectorSizeInformation = 11,
|
||||
}
|
||||
|
||||
const fn size_of<T>() -> u32 {
|
||||
std::mem::size_of::<T>() as u32
|
||||
}
|
||||
|
||||
pub const U32_SIZE: u32 = size_of::<u32>();
|
||||
pub const I64_SIZE: u32 = size_of::<i64>();
|
||||
pub const I8_SIZE: u32 = size_of::<i8>();
|
||||
pub const U8_SIZE: u32 = size_of::<u8>();
|
||||
pub const FILE_ATTR_SIZE: u32 = size_of::<flags::FileAttributes>();
|
||||
pub const BOOL_SIZE: u32 = size_of::<Boolean>();
|
||||
|
|
|
@ -198,3 +198,13 @@ bitflags! {
|
|||
const FILE_NOTIFY_CHANGE_STREAM_WRITE = 0x00000800;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Only defines the subset we require from
|
||||
/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ebc7e6e5-4650-4e54-b17c-cf60f6fbeeaa
|
||||
pub struct FileSystemAttributes: u32 {
|
||||
const FILE_CASE_SENSITIVE_SEARCH = 0x00000001;
|
||||
const FILE_CASE_PRESERVED_NAMES = 0x00000002;
|
||||
const FILE_UNICODE_ON_DISK = 0x00000004;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,7 @@
|
|||
|
||||
use crate::errors::invalid_data_error;
|
||||
use rdp::model::error::RdpResult;
|
||||
use std::convert::TryFrom;
|
||||
use utf16string::{WString, LE};
|
||||
|
||||
/// According to [MS-RDPEFS] 1.1 Glossary:
|
||||
|
@ -48,6 +49,11 @@ pub fn to_utf8(s: &str) -> Vec<u8> {
|
|||
format!("{}\x00", s).into_bytes()
|
||||
}
|
||||
|
||||
/// Takes a Rust string slice and calculates it's unicode size in bytes.
|
||||
pub fn unicode_size(s: &str, with_null_term: bool) -> u32 {
|
||||
u32::try_from(to_unicode(s, with_null_term).len()).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -45,20 +45,30 @@ type MessageType byte
|
|||
// For descriptions of each message type see:
|
||||
// https://github.com/gravitational/teleport/blob/master/rfd/0037-desktop-access-protocol.md#message-types
|
||||
const (
|
||||
TypeClientScreenSpec = MessageType(1)
|
||||
TypePNGFrame = MessageType(2)
|
||||
TypeMouseMove = MessageType(3)
|
||||
TypeMouseButton = MessageType(4)
|
||||
TypeKeyboardButton = MessageType(5)
|
||||
TypeClipboardData = MessageType(6)
|
||||
TypeClientUsername = MessageType(7)
|
||||
TypeMouseWheel = MessageType(8)
|
||||
TypeError = MessageType(9)
|
||||
TypeMFA = MessageType(10)
|
||||
TypeSharedDirectoryAnnounce = MessageType(11)
|
||||
TypeSharedDirectoryAcknowledge = MessageType(12)
|
||||
TypeSharedDirectoryInfoRequest = MessageType(13)
|
||||
TypeSharedDirectoryInfoResponse = MessageType(14)
|
||||
TypeClientScreenSpec = MessageType(1)
|
||||
TypePNGFrame = MessageType(2)
|
||||
TypeMouseMove = MessageType(3)
|
||||
TypeMouseButton = MessageType(4)
|
||||
TypeKeyboardButton = MessageType(5)
|
||||
TypeClipboardData = MessageType(6)
|
||||
TypeClientUsername = MessageType(7)
|
||||
TypeMouseWheel = MessageType(8)
|
||||
TypeError = MessageType(9)
|
||||
TypeMFA = MessageType(10)
|
||||
TypeSharedDirectoryAnnounce = MessageType(11)
|
||||
TypeSharedDirectoryAcknowledge = MessageType(12)
|
||||
TypeSharedDirectoryInfoRequest = MessageType(13)
|
||||
TypeSharedDirectoryInfoResponse = MessageType(14)
|
||||
TypeSharedDirectoryCreateRequest = MessageType(15)
|
||||
TypeSharedDirectoryCreateResponse = MessageType(16)
|
||||
TypeSharedDirectoryDeleteRequest = MessageType(17)
|
||||
TypeSharedDirectoryDeleteResponse = MessageType(18)
|
||||
TypeSharedDirectoryReadRequest = MessageType(19)
|
||||
TypeSharedDirectoryReadResponse = MessageType(20)
|
||||
TypeSharedDirectoryWriteRequest = MessageType(21)
|
||||
TypeSharedDirectoryWriteResponse = MessageType(22)
|
||||
TypeSharedDirectoryListRequest = MessageType(25)
|
||||
TypeSharedDirectoryListResponse = MessageType(26)
|
||||
)
|
||||
|
||||
// Message is a Go representation of a desktop protocol message.
|
||||
|
@ -119,6 +129,26 @@ func decode(in peekReader) (Message, error) {
|
|||
return decodeSharedDirectoryInfoRequest(in)
|
||||
case TypeSharedDirectoryInfoResponse:
|
||||
return decodeSharedDirectoryInfoResponse(in)
|
||||
case TypeSharedDirectoryCreateRequest:
|
||||
return decodeSharedDirectoryCreateRequest(in)
|
||||
case TypeSharedDirectoryCreateResponse:
|
||||
return decodeSharedDirectoryCreateResponse(in)
|
||||
case TypeSharedDirectoryDeleteRequest:
|
||||
return decodeSharedDirectoryDeleteRequest(in)
|
||||
case TypeSharedDirectoryDeleteResponse:
|
||||
return decodeSharedDirectoryDeleteResponse(in)
|
||||
case TypeSharedDirectoryListRequest:
|
||||
return decodeSharedDirectoryListRequest(in)
|
||||
case TypeSharedDirectoryListResponse:
|
||||
return decodeSharedDirectoryListResponse(in)
|
||||
case TypeSharedDirectoryReadRequest:
|
||||
return decodeSharedDirectoryReadRequest(in)
|
||||
case TypeSharedDirectoryReadResponse:
|
||||
return decodeSharedDirectoryReadResponse(in)
|
||||
case TypeSharedDirectoryWriteRequest:
|
||||
return decodeSharedDirectoryWriteRequest(in)
|
||||
case TypeSharedDirectoryWriteResponse:
|
||||
return decodeSharedDirectoryWriteResponse(in)
|
||||
default:
|
||||
return nil, trace.BadParameter("unsupported desktop protocol message type %d", t)
|
||||
}
|
||||
|
@ -821,6 +851,525 @@ func decodeFileSystemObject(in peekReader) (FileSystemObject, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
type SharedDirectoryCreateRequest struct {
|
||||
CompletionID uint32
|
||||
DirectoryID uint32
|
||||
FileType uint32
|
||||
Path string
|
||||
}
|
||||
|
||||
func (s SharedDirectoryCreateRequest) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(TypeSharedDirectoryCreateRequest))
|
||||
binary.Write(buf, binary.BigEndian, s.CompletionID)
|
||||
binary.Write(buf, binary.BigEndian, s.DirectoryID)
|
||||
binary.Write(buf, binary.BigEndian, s.FileType)
|
||||
if err := encodeString(buf, s.Path); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryCreateRequest(in peekReader) (SharedDirectoryCreateRequest, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryCreateRequest{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryCreateRequest) {
|
||||
return SharedDirectoryCreateRequest{}, trace.BadParameter("got message type %v, expected SharedDirectoryCreateRequest(%v)", t, TypeSharedDirectoryCreateRequest)
|
||||
}
|
||||
var completionID, directoryID, fileType uint32
|
||||
err = binary.Read(in, binary.BigEndian, &completionID)
|
||||
if err != nil {
|
||||
return SharedDirectoryCreateRequest{}, trace.Wrap(err)
|
||||
}
|
||||
err = binary.Read(in, binary.BigEndian, &directoryID)
|
||||
if err != nil {
|
||||
return SharedDirectoryCreateRequest{}, trace.Wrap(err)
|
||||
}
|
||||
err = binary.Read(in, binary.BigEndian, &fileType)
|
||||
if err != nil {
|
||||
return SharedDirectoryCreateRequest{}, trace.Wrap(err)
|
||||
}
|
||||
path, err := decodeString(in, tdpMaxPathLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryCreateRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return SharedDirectoryCreateRequest{
|
||||
CompletionID: completionID,
|
||||
DirectoryID: directoryID,
|
||||
FileType: fileType,
|
||||
Path: path,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
type SharedDirectoryCreateResponse struct {
|
||||
CompletionID uint32
|
||||
ErrCode uint32
|
||||
}
|
||||
|
||||
func (s SharedDirectoryCreateResponse) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(TypeSharedDirectoryCreateResponse))
|
||||
binary.Write(buf, binary.BigEndian, s)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryCreateResponse(in peekReader) (SharedDirectoryCreateResponse, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryCreateResponse{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryCreateRequest) {
|
||||
return SharedDirectoryCreateResponse{}, trace.BadParameter("got message type %v, expected SharedDirectoryCreateResponse(%v)", t, TypeSharedDirectoryCreateRequest)
|
||||
}
|
||||
|
||||
var res SharedDirectoryCreateResponse
|
||||
err = binary.Read(in, binary.BigEndian, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
type SharedDirectoryDeleteRequest struct {
|
||||
CompletionID uint32
|
||||
DirectoryID uint32
|
||||
Path string
|
||||
}
|
||||
|
||||
func (s SharedDirectoryDeleteRequest) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(TypeSharedDirectoryDeleteRequest))
|
||||
binary.Write(buf, binary.BigEndian, s.CompletionID)
|
||||
binary.Write(buf, binary.BigEndian, s.DirectoryID)
|
||||
if err := encodeString(buf, s.Path); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryDeleteRequest(in peekReader) (SharedDirectoryDeleteRequest, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryDeleteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryDeleteRequest) {
|
||||
return SharedDirectoryDeleteRequest{}, trace.BadParameter("got message type %v, expected SharedDirectoryDeleteRequest(%v)", t, TypeSharedDirectoryDeleteRequest)
|
||||
}
|
||||
var completionID, directoryID uint32
|
||||
err = binary.Read(in, binary.BigEndian, &completionID)
|
||||
if err != nil {
|
||||
return SharedDirectoryDeleteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
err = binary.Read(in, binary.BigEndian, &directoryID)
|
||||
if err != nil {
|
||||
return SharedDirectoryDeleteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
path, err := decodeString(in, tdpMaxPathLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryDeleteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return SharedDirectoryDeleteRequest{
|
||||
CompletionID: completionID,
|
||||
DirectoryID: directoryID,
|
||||
Path: path,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type SharedDirectoryDeleteResponse struct {
|
||||
CompletionID uint32
|
||||
ErrCode uint32
|
||||
}
|
||||
|
||||
func (s SharedDirectoryDeleteResponse) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(TypeSharedDirectoryDeleteResponse))
|
||||
binary.Write(buf, binary.BigEndian, s)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryDeleteResponse(in peekReader) (SharedDirectoryDeleteResponse, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryDeleteResponse{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryDeleteRequest) {
|
||||
return SharedDirectoryDeleteResponse{}, trace.BadParameter("got message type %v, expected SharedDirectoryDeleteResponse(%v)", t, TypeSharedDirectoryDeleteRequest)
|
||||
}
|
||||
|
||||
var res SharedDirectoryDeleteResponse
|
||||
err = binary.Read(in, binary.BigEndian, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
type SharedDirectoryListRequest struct {
|
||||
CompletionID uint32
|
||||
DirectoryID uint32
|
||||
Path string
|
||||
}
|
||||
|
||||
func (s SharedDirectoryListRequest) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(TypeSharedDirectoryListRequest))
|
||||
binary.Write(buf, binary.BigEndian, s.CompletionID)
|
||||
binary.Write(buf, binary.BigEndian, s.DirectoryID)
|
||||
if err := encodeString(buf, s.Path); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryListRequest(in peekReader) (SharedDirectoryListRequest, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryListRequest{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryListRequest) {
|
||||
return SharedDirectoryListRequest{}, trace.BadParameter("got message type %v, expected SharedDirectoryListRequest(%v)", t, TypeSharedDirectoryListRequest)
|
||||
}
|
||||
var completionID, directoryID uint32
|
||||
err = binary.Read(in, binary.BigEndian, &completionID)
|
||||
if err != nil {
|
||||
return SharedDirectoryListRequest{}, trace.Wrap(err)
|
||||
}
|
||||
err = binary.Read(in, binary.BigEndian, &directoryID)
|
||||
if err != nil {
|
||||
return SharedDirectoryListRequest{}, trace.Wrap(err)
|
||||
}
|
||||
path, err := decodeString(in, tdpMaxPathLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryListRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return SharedDirectoryListRequest{
|
||||
CompletionID: completionID,
|
||||
DirectoryID: directoryID,
|
||||
Path: path,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// | message type (26) | completion_id uint32 | err_code uint32 | fso_list_length uint32 | fso_list fso[] |
|
||||
type SharedDirectoryListResponse struct {
|
||||
CompletionID uint32
|
||||
ErrCode uint32
|
||||
FsoList []FileSystemObject
|
||||
}
|
||||
|
||||
func (s SharedDirectoryListResponse) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(TypeSharedDirectoryListResponse))
|
||||
binary.Write(buf, binary.BigEndian, s.CompletionID)
|
||||
binary.Write(buf, binary.BigEndian, s.ErrCode)
|
||||
binary.Write(buf, binary.BigEndian, uint32(len(s.FsoList)))
|
||||
for _, fso := range s.FsoList {
|
||||
fsoEnc, err := fso.Encode()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
binary.Write(buf, binary.BigEndian, fsoEnc)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryListResponse(in peekReader) (SharedDirectoryListResponse, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryListResponse{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryListResponse) {
|
||||
return SharedDirectoryListResponse{}, trace.BadParameter("got message type %v, expected SharedDirectoryListResponse(%v)", t, TypeSharedDirectoryListResponse)
|
||||
}
|
||||
var completionID, errCode, fsoListLength uint32
|
||||
err = binary.Read(in, binary.BigEndian, &completionID)
|
||||
if err != nil {
|
||||
return SharedDirectoryListResponse{}, trace.Wrap(err)
|
||||
}
|
||||
err = binary.Read(in, binary.BigEndian, &errCode)
|
||||
if err != nil {
|
||||
return SharedDirectoryListResponse{}, trace.Wrap(err)
|
||||
}
|
||||
err = binary.Read(in, binary.BigEndian, &fsoListLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryListResponse{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
var fsoList []FileSystemObject
|
||||
for i := uint32(0); i < fsoListLength; i++ {
|
||||
fso, err := decodeFileSystemObject(in)
|
||||
if err != nil {
|
||||
return SharedDirectoryListResponse{}, trace.Wrap(err)
|
||||
}
|
||||
fsoList = append(fsoList, fso)
|
||||
}
|
||||
|
||||
return SharedDirectoryListResponse{
|
||||
CompletionID: completionID,
|
||||
ErrCode: errCode,
|
||||
FsoList: fsoList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SharedDirectoryReadRequest is a message sent by the server to the client to request
|
||||
// bytes to be read from the file at the path and starting at byte offset.
|
||||
type SharedDirectoryReadRequest struct {
|
||||
CompletionID uint32
|
||||
DirectoryID uint32
|
||||
Path string
|
||||
PathLength uint32
|
||||
Offset uint64
|
||||
Length uint32
|
||||
}
|
||||
|
||||
func (s SharedDirectoryReadRequest) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
buf.WriteByte(byte(TypeSharedDirectoryReadRequest))
|
||||
binary.Write(buf, binary.BigEndian, s.CompletionID)
|
||||
binary.Write(buf, binary.BigEndian, s.DirectoryID)
|
||||
if err := encodeString(buf, s.Path); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
binary.Write(buf, binary.BigEndian, s.Offset)
|
||||
binary.Write(buf, binary.BigEndian, s.Length)
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryReadRequest(in peekReader) (SharedDirectoryReadRequest, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryReadRequest{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryReadRequest) {
|
||||
return SharedDirectoryReadRequest{}, trace.BadParameter("got message type %v, expected TypeSharedDirectoryReadRequest(%v)", t, TypeSharedDirectoryReadRequest)
|
||||
}
|
||||
|
||||
var completionID, directoryID, pathLength, length uint32
|
||||
var offset uint64
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &completionID)
|
||||
if err != nil {
|
||||
return SharedDirectoryReadRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &directoryID)
|
||||
if err != nil {
|
||||
return SharedDirectoryReadRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
path, err := decodeString(in, tdpMaxPathLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryReadRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &pathLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryReadRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &offset)
|
||||
if err != nil {
|
||||
return SharedDirectoryReadRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
return SharedDirectoryReadRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return SharedDirectoryReadRequest{
|
||||
CompletionID: completionID,
|
||||
DirectoryID: directoryID,
|
||||
Path: path,
|
||||
PathLength: pathLength,
|
||||
Offset: offset,
|
||||
Length: length,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SharedDirectoryReadResponse is a message sent by the client to the server
|
||||
// in response to the SharedDirectoryReadRequest.
|
||||
type SharedDirectoryReadResponse struct {
|
||||
CompletionID uint32
|
||||
ErrCode uint32
|
||||
ReadDataLength uint32
|
||||
ReadData []byte
|
||||
}
|
||||
|
||||
func (s SharedDirectoryReadResponse) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(TypeSharedDirectoryReadResponse))
|
||||
binary.Write(buf, binary.BigEndian, s.CompletionID)
|
||||
binary.Write(buf, binary.BigEndian, s.ErrCode)
|
||||
binary.Write(buf, binary.BigEndian, s.ReadDataLength)
|
||||
if _, err := buf.Write(s.ReadData); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryReadResponse(in peekReader) (SharedDirectoryReadResponse, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryReadResponse{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryReadResponse) {
|
||||
return SharedDirectoryReadResponse{}, trace.BadParameter("got message type %v, expected TypeSharedDirectoryReadResponse(%v)", t, TypeSharedDirectoryReadResponse)
|
||||
}
|
||||
|
||||
var completionID, errorCode, readDataLength uint32
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &completionID)
|
||||
if err != nil {
|
||||
return SharedDirectoryReadResponse{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &errorCode)
|
||||
if err != nil {
|
||||
return SharedDirectoryReadResponse{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &readDataLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryReadResponse{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
readData := make([]byte, int(readDataLength))
|
||||
if _, err := io.ReadFull(in, readData); err != nil {
|
||||
return SharedDirectoryReadResponse{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return SharedDirectoryReadResponse{
|
||||
CompletionID: completionID,
|
||||
ErrCode: errorCode,
|
||||
ReadDataLength: readDataLength,
|
||||
ReadData: readData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SharedDirectoryWriteRequest is a message sent by the server to the client to request
|
||||
// bytes to be written the file at the path and starting at byte offset.
|
||||
type SharedDirectoryWriteRequest struct {
|
||||
CompletionID uint32
|
||||
DirectoryID uint32
|
||||
Offset uint64
|
||||
Path string
|
||||
PathLength uint32
|
||||
WriteDataLength uint32
|
||||
WriteData []byte
|
||||
}
|
||||
|
||||
func (s SharedDirectoryWriteRequest) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
buf.WriteByte(byte(TypeSharedDirectoryWriteRequest))
|
||||
binary.Write(buf, binary.BigEndian, s.CompletionID)
|
||||
binary.Write(buf, binary.BigEndian, s.DirectoryID)
|
||||
binary.Write(buf, binary.BigEndian, s.Offset)
|
||||
if err := encodeString(buf, s.Path); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
binary.Write(buf, binary.BigEndian, s.WriteDataLength)
|
||||
if _, err := buf.Write(s.WriteData); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryWriteRequest(in peekReader) (SharedDirectoryWriteRequest, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryWriteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryWriteRequest) {
|
||||
return SharedDirectoryWriteRequest{}, trace.BadParameter("got message type %v, expected TypeSharedDirectoryWriteRequest(%v)", t, TypeSharedDirectoryWriteRequest)
|
||||
}
|
||||
|
||||
var completionID, directoryID, pathLength, writeDataLength uint32
|
||||
var offset uint64
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &completionID)
|
||||
if err != nil {
|
||||
return SharedDirectoryWriteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &directoryID)
|
||||
if err != nil {
|
||||
return SharedDirectoryWriteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &offset)
|
||||
if err != nil {
|
||||
return SharedDirectoryWriteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
path, err := decodeString(in, tdpMaxPathLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryWriteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &pathLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryWriteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = binary.Read(in, binary.BigEndian, &writeDataLength)
|
||||
if err != nil {
|
||||
return SharedDirectoryWriteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
writeData := make([]byte, int(writeDataLength))
|
||||
if _, err := io.ReadFull(in, writeData); err != nil {
|
||||
return SharedDirectoryWriteRequest{}, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return SharedDirectoryWriteRequest{
|
||||
CompletionID: completionID,
|
||||
DirectoryID: directoryID,
|
||||
Path: path,
|
||||
PathLength: pathLength,
|
||||
Offset: offset,
|
||||
WriteDataLength: writeDataLength,
|
||||
WriteData: writeData,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
// SharedDirectoryWriteResponse is a message sent by the client to the server
|
||||
// in response to the SharedDirectoryWriteRequest.
|
||||
type SharedDirectoryWriteResponse struct {
|
||||
CompletionID uint32
|
||||
ErrCode uint32
|
||||
BytesWritten uint32
|
||||
}
|
||||
|
||||
func (s SharedDirectoryWriteResponse) Encode() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(TypeSharedDirectoryWriteResponse))
|
||||
binary.Write(buf, binary.BigEndian, s)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func decodeSharedDirectoryWriteResponse(in peekReader) (SharedDirectoryWriteResponse, error) {
|
||||
t, err := in.ReadByte()
|
||||
if err != nil {
|
||||
return SharedDirectoryWriteResponse{}, trace.Wrap(err)
|
||||
}
|
||||
if t != byte(TypeSharedDirectoryWriteResponse) {
|
||||
return SharedDirectoryWriteResponse{}, trace.BadParameter("got message type %v, expected SharedDirectoryWriteResponse(%v)", t, TypeSharedDirectoryWriteResponse)
|
||||
}
|
||||
|
||||
var res SharedDirectoryWriteResponse
|
||||
err = binary.Read(in, binary.BigEndian, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// encodeString encodes strings for TDP. Strings are encoded as UTF-8 with
|
||||
// a 32-bit length prefix (in bytes):
|
||||
// https://github.com/gravitational/teleport/blob/master/rfd/0037-desktop-access-protocol.md#field-types
|
||||
|
|
Loading…
Reference in a new issue