30 "PC_SMB_BUF is too small to frame a CREATE around a full-length path "
31 "(64B header + 56B body + PC_SMB_BUF/2 path must fit PC_SMB_BUF-4)");
34 "PC_SMB_BUF is too small to frame a WRITE around a full chunk");
37 "PC_SMB_BUF is too small to frame a SESSION_SETUP around a full security blob");
40static size_t utf16le(
const char *s, uint8_t *out,
size_t cap)
52 if ((n * 2 + 2) > cap)
56 out[n * 2] = (uint8_t)s[n];
63static void find_av_timestamp(
const uint8_t *ti,
size_t ti_len, uint8_t out[8])
67 while (p + 4 <= ti_len)
69 uint16_t
id = (uint16_t)(ti[p] | (ti[p + 1] << 8));
70 uint16_t len = (uint16_t)(ti[p + 2] | (ti[p + 3] << 8));
76 if (
id == 7 && len == 8 && p + 8 <= ti_len)
78 memcpy(out, ti + p, 8);
85static bool read_exact(SmbRecvFn recv,
void *ctx, uint8_t *buf,
size_t n)
90 int r = recv(ctx, buf + got, n - got);
101static bool send_msg(SmbSendFn send,
void *ctx, uint8_t *frame,
size_t msg_len)
104 frame[1] = (uint8_t)(msg_len >> 16);
105 frame[2] = (uint8_t)(msg_len >> 8);
106 frame[3] = (uint8_t)msg_len;
107 size_t total = 4 + msg_len;
108 return send(ctx, frame, total) == (int)total;
112static int recv_msg(SmbRecvFn recv,
void *ctx, uint8_t *rx,
size_t cap)
115 if (!read_exact(recv, ctx, pre, 4) || pre[0] != 0x00)
119 size_t len = ((size_t)pre[1] << 16) | ((size_t)pre[2] << 8) | pre[3];
120 if (len == 0 || len > cap)
122 return len ? -2 : -1;
124 if (!read_exact(recv, ctx, rx, len))
145static SmbClientCtx s_smb;
169 uint8_t c2s[PC_SMB2_MAX_CIPHER_KEY_LEN];
170 uint8_t s2c[PC_SMB2_MAX_CIPHER_KEY_LEN];
176static void smb_apply_sign(
const SmbSign *s, uint8_t *msg,
size_t len)
178 if (s->algo == Smb2SignAlgo::AES_CMAC)
180 pc_smb2_sign_cmac(s->key, msg, len);
184 pc_smb2_sign(s->key, msg, len);
187static bool smb_check_sign(
const SmbSign *s, uint8_t *msg,
size_t len)
189 return s->algo == Smb2SignAlgo::AES_CMAC ? pc_smb2_verify_cmac(s->key, msg, len) : pc_smb2_verify(s->key, msg, len);
196static int smb_round_trip(SmbSendFn send, SmbRecvFn recv,
void *ctx,
size_t mlen,
const SmbSign *sign, SmbCrypt *crypt,
202 if (crypt && crypt->active)
204 uint8_t nonce[PC_SMB2_NONCE_FIELD_LEN] = {0};
205 const uint64_t ctr = crypt->nonce++;
206 for (
int i = 0; i < 8; i++)
208 nonce[i] = (uint8_t)(ctr >> (8 * i));
210 size_t tlen = pc_smb2_encrypt(crypt->cipher, crypt->c2s, nonce, crypt->session_id, s_smb.tx + 4, mlen,
211 s_smb.rx + 4,
sizeof(s_smb.rx) - 4);
214 *res = SmbResult::SMB_ERR_OVERFLOW;
217 if (!send_msg(send, ctx, s_smb.rx, tlen))
219 *res = SmbResult::SMB_ERR_IO;
222 int rl = recv_msg(recv, ctx, s_smb.rx,
sizeof(s_smb.rx));
225 *res = (rl == -2) ? SmbResult::SMB_ERR_OVERFLOW : SmbResult::SMB_ERR_IO;
230 size_t plen = pc_smb2_decrypt(crypt->cipher, crypt->s2c, s_smb.rx, (
size_t)rl, s_smb.rx,
sizeof(s_smb.rx));
233 *res = SmbResult::SMB_ERR_PROTOCOL;
239 if (sign && sign->active)
241 smb_apply_sign(sign, s_smb.tx + 4, mlen);
243 if (!send_msg(send, ctx, s_smb.tx, mlen))
245 *res = SmbResult::SMB_ERR_IO;
248 int rl = recv_msg(recv, ctx, s_smb.rx,
sizeof(s_smb.rx));
251 *res = (rl == -2) ? SmbResult::SMB_ERR_OVERFLOW : SmbResult::SMB_ERR_IO;
254 if (sign && sign->active && !smb_check_sign(sign, s_smb.rx, (
size_t)rl))
256 *res = SmbResult::SMB_ERR_PROTOCOL;
268static SmbResult smb_negotiate(SmbSendFn send, SmbRecvFn recv,
void *ctx, uint16_t *sec_mode, uint16_t *dialect,
269 uint16_t *cipher, SmbPreauth *preauth,
const uint16_t *offer_ciphers,
size_t offer_count)
273 esp_fill_random(guid, 16);
274 esp_fill_random(salt,
sizeof(salt));
275 size_t mlen = pc_smb2_build_negotiate_311(s_smb.tx + 4,
sizeof(s_smb.tx) - 4, guid,
276 Smb2SecurityMode::SMB2_NEGOTIATE_SIGNING_ENABLED, salt,
sizeof(salt),
277 offer_ciphers, offer_count);
280 return SmbResult::SMB_ERR_OVERFLOW;
286 pc_smb_preauth_init(preauth);
287 pc_smb_preauth_update(preauth, s_smb.tx + 4, mlen);
289 SmbResult rt = SmbResult::SMB_ERR_IO;
291 int rl = smb_round_trip(send, recv, ctx, mlen,
nullptr,
nullptr, &rt);
296 pc_smb_preauth_update(preauth, s_smb.rx, (
size_t)rl);
297 Smb2NegotiateResp neg;
298 if (!pc_smb2_parse_negotiate_response(s_smb.rx, (
size_t)rl, &neg))
300 return SmbResult::SMB_ERR_PROTOCOL;
302 *sec_mode = neg.security_mode;
303 *dialect = neg.dialect;
308 if (neg.dialect == (uint16_t)Smb2Dialect::SMB2_DIALECT_0311)
310 Smb2NegotiateContexts nc;
311 if (pc_smb2_parse_negotiate_contexts(s_smb.rx, (
size_t)rl, &nc) && nc.have_encryption)
316 return SmbResult::SMB_OK;
325static SmbResult smb_session_setup(
const SmbConfig *cfg,
const char *domain,
bool want_signing, uint16_t dialect,
326 uint16_t cipher, SmbPreauth *preauth, SmbSendFn send, SmbRecvFn recv,
void *ctx,
327 uint64_t *session_id, SmbSign *sign, SmbCrypt *crypt)
332 size_t ntneg_n = pc_ntlmssp_build_negotiate(ntneg,
sizeof(ntneg), NtlmsspFlags::NTLMSSP_CLIENT_DEFAULT_FLAGS);
333 size_t sp1_n = pc_spnego_wrap_negotiate(ntneg, ntneg_n, sp1,
sizeof(sp1));
334 size_t mlen = pc_smb2_build_session_setup(s_smb.tx + 4,
sizeof(s_smb.tx) - 4, 1, 0,
335 Smb2SecurityMode::SMB2_NEGOTIATE_SIGNING_ENABLED, sp1, sp1_n);
338 return SmbResult::SMB_ERR_OVERFLOW;
340 pc_smb_preauth_update(preauth, s_smb.tx + 4, mlen);
341 SmbResult rt = SmbResult::SMB_ERR_IO;
343 int rl = smb_round_trip(send, recv, ctx, mlen,
nullptr,
nullptr, &rt);
348 pc_smb_preauth_update(preauth, s_smb.rx, (
size_t)rl);
350 if (!pc_smb2_parse_header(s_smb.rx, (
size_t)rl, &h1) ||
351 h1.status != Smb2Status::SMB2_STATUS_MORE_PROCESSING_REQUIRED)
353 return SmbResult::SMB_ERR_AUTH;
355 *session_id = h1.session_id;
356 Smb2SessionSetupResp ss1;
357 if (!pc_smb2_parse_session_setup_response(s_smb.rx, (
size_t)rl, &ss1) || !ss1.sec_buf)
359 return SmbResult::SMB_ERR_PROTOCOL;
361 const uint8_t *chal_tok =
nullptr;
363 if (!pc_spnego_parse_response(ss1.sec_buf, ss1.sec_buf_len, &chal_tok, &chal_len))
365 return SmbResult::SMB_ERR_PROTOCOL;
368 if (!pc_ntlmssp_parse_challenge(chal_tok, chal_len, &ch))
370 return SmbResult::SMB_ERR_PROTOCOL;
376 pc_ntlm_nt_hash(cfg->pass, nt_hash);
377 if (!pc_ntlm_ntowfv2(nt_hash, cfg->user, domain, owf))
379 return SmbResult::SMB_ERR_OVERFLOW;
384 esp_fill_random(cli_chal, 8);
385 find_av_timestamp(ch.target_info, ch.target_info_len, ts);
388 size_t ti_len = pc_ntlm_set_mic_flag(ch.target_info, ch.target_info_len, s_smb.ti,
sizeof(s_smb.ti));
391 return SmbResult::SMB_ERR_OVERFLOW;
393 size_t nt_len = pc_ntlm_v2_response(owf, ch.server_challenge, cli_chal, ts, s_smb.ti, ti_len, s_smb.nt_resp,
394 sizeof(s_smb.nt_resp), skey);
397 return SmbResult::SMB_ERR_OVERFLOW;
399 size_t ntauth_n = pc_ntlmssp_build_authenticate(s_smb.ntauth,
sizeof(s_smb.ntauth),
nullptr, 0, s_smb.nt_resp,
400 nt_len, domain, cfg->user, cfg->workstation, ch.flags,
true);
403 return SmbResult::SMB_ERR_OVERFLOW;
406 uint8_t mic[PC_NTLMSSP_MIC_LEN];
407 pc_ntlm_mic(skey, ntneg, ntneg_n, chal_tok, chal_len, s_smb.ntauth, ntauth_n, mic);
408 memcpy(s_smb.ntauth + PC_NTLMSSP_MIC_OFFSET, mic, PC_NTLMSSP_MIC_LEN);
409 size_t sp2_n = pc_spnego_wrap_authenticate(s_smb.ntauth, ntauth_n, s_smb.sp2,
sizeof(s_smb.sp2));
412 return SmbResult::SMB_ERR_OVERFLOW;
417 mlen = pc_smb2_build_session_setup(s_smb.tx + 4,
sizeof(s_smb.tx) - 4, 2, *session_id,
418 Smb2SecurityMode::SMB2_NEGOTIATE_SIGNING_ENABLED, s_smb.sp2, sp2_n);
421 return SmbResult::SMB_ERR_OVERFLOW;
423 pc_smb_preauth_update(preauth, s_smb.tx + 4, mlen);
430 const Smb2SignAlgo algo =
431 dialect >= (uint16_t)Smb2Dialect::SMB2_DIALECT_0300 ? Smb2SignAlgo::AES_CMAC : Smb2SignAlgo::HMAC_SHA256;
432 uint8_t sign_key[16];
433 if (algo == Smb2SignAlgo::AES_CMAC)
435 const bool is_311 = dialect == (uint16_t)Smb2Dialect::SMB2_DIALECT_0311;
436 pc_smb3_derive_signing_key(skey, dialect, is_311 ? preauth->hash : nullptr, sign_key);
440 memcpy(sign_key, skey,
sizeof(sign_key));
443 pc_smb2_sign(skey, s_smb.tx + 4, mlen);
447 rl = smb_round_trip(send, recv, ctx, mlen,
nullptr,
nullptr, &rt);
453 if (!pc_smb2_parse_header(s_smb.rx, (
size_t)rl, &h2))
455 return SmbResult::SMB_ERR_PROTOCOL;
457 if (h2.status != Smb2Status::SMB2_STATUS_SUCCESS)
459 return SmbResult::SMB_ERR_AUTH;
463 Smb2SessionSetupResp ss2;
464 bool guest_or_null =
false;
465 uint16_t sess_flags = 0;
466 if (pc_smb2_parse_session_setup_response(s_smb.rx, (
size_t)rl, &ss2))
468 sess_flags = ss2.session_flags;
469 guest_or_null = (sess_flags & (Smb2SessionFlags::SMB2_SESSION_FLAG_IS_GUEST |
470 Smb2SessionFlags::SMB2_SESSION_FLAG_IS_NULL)) != 0;
472 sign->active = want_signing && !guest_or_null;
474 memcpy(sign->key, sign_key,
sizeof(sign->key));
482 crypt->active =
false;
483 crypt->available =
false;
485 crypt->session_id = *session_id;
487 const size_t cipher_key_len = pc_smb2_cipher_key_len(cipher);
488 if (cipher_key_len != 0 && dialect >= (uint16_t)Smb2Dialect::SMB2_DIALECT_0300 && !guest_or_null)
490 const bool is_311 = dialect == (uint16_t)Smb2Dialect::SMB2_DIALECT_0311;
491 crypt->available = pc_smb3_derive_encryption_keys(skey, dialect, is_311 ? preauth->hash : nullptr,
492 cipher_key_len, crypt->c2s, crypt->s2c);
493 if (crypt->available)
495 crypt->cipher = cipher;
496 if ((sess_flags & Smb2SessionFlags::SMB2_SESSION_FLAG_ENCRYPT_DATA) || cfg->encrypt)
498 crypt->active =
true;
502 return SmbResult::SMB_OK;
506static SmbResult smb_tree_connect(
const SmbConfig *cfg, uint64_t session_id,
const SmbSign *sign, SmbSendFn send,
507 SmbRecvFn recv,
void *ctx, uint32_t *tree_id, SmbCrypt *crypt)
509 size_t utf16_n = utf16le(cfg->share, s_smb.utf16,
sizeof(s_smb.utf16));
512 return SmbResult::SMB_ERR_OVERFLOW;
514 size_t mlen = pc_smb2_build_tree_connect(s_smb.tx + 4,
sizeof(s_smb.tx) - 4, 3, session_id, s_smb.utf16, utf16_n);
517 return SmbResult::SMB_ERR_OVERFLOW;
519 SmbResult rt = SmbResult::SMB_ERR_IO;
520 int rl = smb_round_trip(send, recv, ctx, mlen, sign, crypt, &rt);
526 Smb2TreeConnectResp tc;
527 if (!pc_smb2_parse_header(s_smb.rx, (
size_t)rl, &h3) || h3.status != Smb2Status::SMB2_STATUS_SUCCESS)
529 return SmbResult::SMB_ERR_PROTOCOL;
531 if (!pc_smb2_parse_tree_connect_response(s_smb.rx, (
size_t)rl, &tc))
533 return SmbResult::SMB_ERR_PROTOCOL;
535 *tree_id = h3.tree_id;
538 if (crypt && crypt->available && (tc.share_flags & Smb2ShareFlags::SMB2_SHAREFLAG_ENCRYPT_DATA))
540 crypt->active =
true;
542 return SmbResult::SMB_OK;
546static SmbResult smb_create(
const SmbConfig *cfg, SmbHandle *h, uint64_t session_id, uint32_t tree_id,
547 const SmbSign *sign, SmbCrypt *crypt, SmbSendFn send, SmbRecvFn recv,
void *ctx)
549 size_t utf16_n = utf16le(cfg->path, s_smb.utf16,
sizeof(s_smb.utf16));
552 return SmbResult::SMB_ERR_OVERFLOW;
555 pc_smb2_build_create(s_smb.tx + 4,
sizeof(s_smb.tx) - 4, 4, session_id, tree_id, cfg->desired_access,
556 Smb2ShareAccess::SMB2_FILE_SHARE_READ | Smb2ShareAccess::SMB2_FILE_SHARE_WRITE,
557 cfg->disposition, Smb2CreateOptions::SMB2_FILE_NON_DIRECTORY_FILE, s_smb.utf16, utf16_n);
560 return SmbResult::SMB_ERR_OVERFLOW;
562 SmbResult rt = SmbResult::SMB_ERR_IO;
563 int rl = smb_round_trip(send, recv, ctx, mlen, sign, crypt, &rt);
570 if (!pc_smb2_parse_header(s_smb.rx, (
size_t)rl, &h4) || h4.status != Smb2Status::SMB2_STATUS_SUCCESS)
572 return SmbResult::SMB_ERR_PROTOCOL;
574 if (!pc_smb2_parse_create_response(s_smb.rx, (
size_t)rl, &cr))
576 return SmbResult::SMB_ERR_PROTOCOL;
578 h->session_id = session_id;
579 h->tree_id = tree_id;
580 memcpy(h->file_id, cr.file_id, 16);
581 h->file_size = cr.end_of_file;
582 h->next_message_id = 5;
583 h->signing_active = sign->active;
584 h->signing_algo = sign->algo;
585 memcpy(h->signing_key, sign->key,
sizeof(h->signing_key));
588 h->encrypt_active = crypt->active;
589 h->enc_cipher = crypt->cipher;
590 memcpy(h->enc_c2s, crypt->c2s,
sizeof(h->enc_c2s));
591 memcpy(h->enc_s2c, crypt->s2c,
sizeof(h->enc_s2c));
592 h->enc_nonce = crypt->nonce;
593 return SmbResult::SMB_OK;
596SmbResult smb_open(
const SmbConfig *cfg, SmbHandle *h, SmbSendFn send, SmbRecvFn recv,
void *ctx)
598 if (!cfg || !h || !send || !recv || !cfg->user || !cfg->pass || !cfg->share || !cfg->path)
600 return SmbResult::SMB_ERR_ARG;
603 const char *domain = cfg->domain ? cfg->domain :
"";
608 uint16_t offer[PC_SMB2_MAX_OFFER_CIPHERS] = {
609 Smb2Cipher::SMB2_ENCRYPTION_AES128_GCM, Smb2Cipher::SMB2_ENCRYPTION_AES256_GCM,
610 Smb2Cipher::SMB2_ENCRYPTION_AES128_CCM, Smb2Cipher::SMB2_ENCRYPTION_AES256_CCM};
611 if (cfg->cipher_pref != 0 && pc_smb2_cipher_key_len(cfg->cipher_pref) != 0)
613 for (
size_t i = 1; i < PC_SMB2_MAX_OFFER_CIPHERS; i++)
615 if (offer[i] == cfg->cipher_pref)
617 for (
size_t j = i; j > 0; j--)
619 offer[j] = offer[j - 1];
621 offer[0] = cfg->cipher_pref;
627 uint16_t sec_mode = 0;
628 uint16_t dialect = 0;
632 smb_negotiate(send, recv, ctx, &sec_mode, &dialect, &cipher, &preauth, offer, PC_SMB2_MAX_OFFER_CIPHERS);
633 if (r != SmbResult::SMB_OK)
638 bool want_signing = (sec_mode & Smb2SecurityMode::SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0;
640 SmbSign sign = {
false, Smb2SignAlgo::HMAC_SHA256, {0}};
641 SmbCrypt crypt = {
false,
false, 0, {0}, {0}, 0, 0};
642 uint64_t session_id = 0;
643 r = smb_session_setup(cfg, domain, want_signing, dialect, cipher, &preauth, send, recv, ctx, &session_id, &sign,
645 if (r != SmbResult::SMB_OK)
650 uint32_t tree_id = 0;
651 r = smb_tree_connect(cfg, session_id, &sign, send, recv, ctx, &tree_id, &crypt);
652 if (r != SmbResult::SMB_OK)
657 return smb_create(cfg, h, session_id, tree_id, &sign, &crypt, send, recv, ctx);
660SmbResult smb_close(SmbHandle *h, SmbSendFn send, SmbRecvFn recv,
void *ctx)
662 if (!h || !send || !recv)
664 return SmbResult::SMB_ERR_ARG;
666 size_t mlen = pc_smb2_build_close(s_smb.tx + 4,
sizeof(s_smb.tx) - 4, h->next_message_id, h->session_id, h->tree_id,
670 return SmbResult::SMB_ERR_OVERFLOW;
672 SmbSign sign = {h->signing_active, h->signing_algo, {0}};
673 memcpy(sign.key, h->signing_key,
sizeof(sign.key));
674 SmbCrypt crypt = {h->encrypt_active, h->encrypt_active, h->enc_cipher, {0}, {0}, h->session_id, h->enc_nonce};
675 memcpy(crypt.c2s, h->enc_c2s,
sizeof(crypt.c2s));
676 memcpy(crypt.s2c, h->enc_s2c,
sizeof(crypt.s2c));
677 SmbResult rt = SmbResult::SMB_ERR_IO;
678 int rl = smb_round_trip(send, recv, ctx, mlen, &sign, &crypt, &rt);
679 h->enc_nonce = crypt.nonce;
686 if (!pc_smb2_parse_header(s_smb.rx, (
size_t)rl, &hd) || hd.status != Smb2Status::SMB2_STATUS_SUCCESS)
688 return SmbResult::SMB_ERR_PROTOCOL;
690 if (!pc_smb2_parse_close_response(s_smb.rx, (
size_t)rl, &cl))
692 return SmbResult::SMB_ERR_PROTOCOL;
694 h->next_message_id++;
695 return SmbResult::SMB_OK;
698SmbResult smb_read(SmbHandle *h, uint64_t offset, uint8_t *out,
size_t cap,
size_t *out_len, SmbSendFn send,
699 SmbRecvFn recv,
void *ctx)
701 if (!h || !out || !out_len || !send || !recv)
703 return SmbResult::SMB_ERR_ARG;
706 SmbSign sign = {h->signing_active, h->signing_algo, {0}};
707 memcpy(sign.key, h->signing_key,
sizeof(sign.key));
708 SmbCrypt crypt = {h->encrypt_active, h->encrypt_active, h->enc_cipher, {0}, {0}, h->session_id, h->enc_nonce};
709 memcpy(crypt.c2s, h->enc_c2s,
sizeof(crypt.c2s));
710 memcpy(crypt.s2c, h->enc_s2c,
sizeof(crypt.s2c));
715 size_t want = cap - total;
716 if (want > chunk_max)
720 size_t mlen = pc_smb2_build_read(s_smb.tx + 4,
sizeof(s_smb.tx) - 4, h->next_message_id, h->session_id,
721 h->tree_id, h->file_id, (uint32_t)want, offset + total);
724 return SmbResult::SMB_ERR_OVERFLOW;
726 SmbResult rt = SmbResult::SMB_ERR_IO;
727 int rl = smb_round_trip(send, recv, ctx, mlen, &sign, &crypt, &rt);
728 h->enc_nonce = crypt.nonce;
734 if (!pc_smb2_parse_header(s_smb.rx, (
size_t)rl, &hd))
736 return SmbResult::SMB_ERR_PROTOCOL;
738 h->next_message_id++;
739 if (hd.status == Smb2Status::SMB2_STATUS_END_OF_FILE)
743 if (hd.status != Smb2Status::SMB2_STATUS_SUCCESS)
745 return SmbResult::SMB_ERR_PROTOCOL;
748 if (!pc_smb2_parse_read_response(s_smb.rx, (
size_t)rl, &r) || r.data_len > want)
750 return SmbResult::SMB_ERR_PROTOCOL;
756 memcpy(out + total, r.data, r.data_len);
758 if (r.data_len < want)
764 return SmbResult::SMB_OK;
767SmbResult smb_write(SmbHandle *h, uint64_t offset,
const uint8_t *data,
size_t len,
size_t *written, SmbSendFn send,
768 SmbRecvFn recv,
void *ctx)
770 if (!h || !data || !written || !send || !recv)
772 return SmbResult::SMB_ERR_ARG;
775 SmbSign sign = {h->signing_active, h->signing_algo, {0}};
776 memcpy(sign.key, h->signing_key,
sizeof(sign.key));
777 SmbCrypt crypt = {h->encrypt_active, h->encrypt_active, h->enc_cipher, {0}, {0}, h->session_id, h->enc_nonce};
778 memcpy(crypt.c2s, h->enc_c2s,
sizeof(crypt.c2s));
779 memcpy(crypt.s2c, h->enc_s2c,
sizeof(crypt.s2c));
784 size_t want = len - total;
785 if (want > chunk_max)
789 size_t mlen = pc_smb2_build_write(s_smb.tx + 4,
sizeof(s_smb.tx) - 4, h->next_message_id, h->session_id,
790 h->tree_id, h->file_id, data + total, want, offset + total);
793 return SmbResult::SMB_ERR_OVERFLOW;
795 SmbResult rt = SmbResult::SMB_ERR_IO;
796 int rl = smb_round_trip(send, recv, ctx, mlen, &sign, &crypt, &rt);
797 h->enc_nonce = crypt.nonce;
803 if (!pc_smb2_parse_header(s_smb.rx, (
size_t)rl, &hd))
805 return SmbResult::SMB_ERR_PROTOCOL;
807 h->next_message_id++;
808 if (hd.status != Smb2Status::SMB2_STATUS_SUCCESS)
810 return SmbResult::SMB_ERR_PROTOCOL;
813 if (!pc_smb2_parse_write_response(s_smb.rx, (
size_t)rl, &w) || w.count == 0 || w.count > want)
815 return SmbResult::SMB_ERR_PROTOCOL;
819 if (offset + total > h->file_size)
821 h->file_size = offset + total;
824 return SmbResult::SMB_OK;
NTLMv2 response computation (MS-NLMP §3.3.2) for the SMB2 client (PC_ENABLE_SMB).
NTLMSSP message codec (MS-NLMP §2.2.1) for the SMB2 client (PC_ENABLE_SMB).
#define PC_SMB_BUF
SMB2 client work-buffer size (bytes) for smb_client's request/response framing.
SMB2 client wire codec (MS-SMB2), PC_ENABLE_SMB - increment 1: the transport frame,...
SMB2 client dialogue engine (PC_ENABLE_SMB) - drives the smb2 / ntlm / spnego wire codecs through a r...
SPNEGO (RFC 4178) GSS-API wrapping of the NTLMSSP tokens for the SMB2 client (PC_ENABLE_SMB).