static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *in, struct ldb_val *out) { struct GUID guid; NTSTATUS status; if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) { return 0; } /* Try as 'hex' form */ if (in->length != 32) { return -1; } *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1); if (!out->data) { return -1; } (*out).length = strhex_to_str((char *)out->data, out->length, (const char *)in->data, in->length); /* Check it looks like a GUID */ status = GUID_from_ndr_blob(out, &guid); if (!NT_STATUS_IS_OK(status)) { data_blob_free(out); return -1; } return 0; }
/* pull a GUID structure from the wire. The buffer must be at least 16 bytes long */ NTSTATUS smbcli_pull_guid(void *base, uint16_t offset, struct GUID *guid) { DATA_BLOB blob; ZERO_STRUCTP(guid); blob.data = offset + (uint8_t *)base; blob.length = 16; return GUID_from_ndr_blob(&blob, guid); }
/* convert a NDR formatted blob to a ldif formatted objectGUID */ static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *in, struct ldb_val *out) { struct GUID guid; NTSTATUS status; status = GUID_from_ndr_blob(in, &guid); if (!NT_STATUS_IS_OK(status)) { return -1; } out->data = (uint8_t *)GUID_string(mem_ctx, &guid); if (out->data == NULL) { return -1; } out->length = strlen((const char *)out->data); return 0; }
NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) { struct smbXsrv_connection *xconn = req->xconn; NTSTATUS status; const uint8_t *inbody; const uint8_t *indyn = NULL; DATA_BLOB outbody; DATA_BLOB outdyn; DATA_BLOB negprot_spnego_blob; uint16_t security_offset; DATA_BLOB security_buffer; size_t expected_dyn_size = 0; size_t c; uint16_t security_mode; uint16_t dialect_count; uint16_t in_security_mode; uint32_t in_capabilities; DATA_BLOB in_guid_blob; struct GUID in_guid; struct smb2_negotiate_contexts in_c = { .num_contexts = 0, }; struct smb2_negotiate_context *in_preauth = NULL; struct smb2_negotiate_context *in_cipher = NULL; struct smb2_negotiate_contexts out_c = { .num_contexts = 0, }; DATA_BLOB out_negotiate_context_blob = data_blob_null; uint32_t out_negotiate_context_offset = 0; uint16_t out_negotiate_context_count = 0; uint16_t dialect = 0; uint32_t capabilities; DATA_BLOB out_guid_blob; struct GUID out_guid; enum protocol_types protocol = PROTOCOL_NONE; uint32_t max_limit; uint32_t max_trans = lp_smb2_max_trans(); uint32_t max_read = lp_smb2_max_read(); uint32_t max_write = lp_smb2_max_write(); NTTIME now = timeval_to_nttime(&req->request_time); bool signing_required = true; bool ok; status = smbd_smb2_request_verify_sizes(req, 0x24); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } inbody = SMBD_SMB2_IN_BODY_PTR(req); dialect_count = SVAL(inbody, 0x02); in_security_mode = SVAL(inbody, 0x04); in_capabilities = IVAL(inbody, 0x08); in_guid_blob = data_blob_const(inbody + 0x0C, 16); if (dialect_count == 0) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } status = GUID_from_ndr_blob(&in_guid_blob, &in_guid); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } expected_dyn_size = dialect_count * 2; if (SMBD_SMB2_IN_DYN_LEN(req) < expected_dyn_size) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } indyn = SMBD_SMB2_IN_DYN_PTR(req); protocol = smbd_smb2_protocol_dialect_match(indyn, dialect_count, &dialect); for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { if (lp_server_max_protocol() < PROTOCOL_SMB2_10) { break; } dialect = SVAL(indyn, c*2); if (dialect == SMB2_DIALECT_REVISION_2FF) { if (xconn->smb2.allow_2ff) { xconn->smb2.allow_2ff = false; protocol = PROTOCOL_SMB2_10; break; } } } if (protocol == PROTOCOL_NONE) { return smbd_smb2_request_error(req, NT_STATUS_NOT_SUPPORTED); } if (protocol >= PROTOCOL_SMB3_10) { uint32_t in_negotiate_context_offset = 0; uint16_t in_negotiate_context_count = 0; DATA_BLOB in_negotiate_context_blob = data_blob_null; size_t ofs; in_negotiate_context_offset = IVAL(inbody, 0x1C); in_negotiate_context_count = SVAL(inbody, 0x20); ofs = SMB2_HDR_BODY; ofs += SMBD_SMB2_IN_BODY_LEN(req); ofs += expected_dyn_size; if ((ofs % 8) != 0) { ofs += 8 - (ofs % 8); } if (in_negotiate_context_offset != ofs) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } ofs -= SMB2_HDR_BODY; ofs -= SMBD_SMB2_IN_BODY_LEN(req); if (SMBD_SMB2_IN_DYN_LEN(req) < ofs) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } in_negotiate_context_blob = data_blob_const(indyn, SMBD_SMB2_IN_DYN_LEN(req)); in_negotiate_context_blob.data += ofs; in_negotiate_context_blob.length -= ofs; status = smb2_negotiate_context_parse(req, in_negotiate_context_blob, &in_c); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } if (in_negotiate_context_count != in_c.num_contexts) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } } if ((dialect != SMB2_DIALECT_REVISION_2FF) && (protocol >= PROTOCOL_SMB2_10) && !GUID_all_zero(&in_guid)) { ok = remote_arch_cache_update(&in_guid); if (!ok) { return smbd_smb2_request_error( req, NT_STATUS_UNSUCCESSFUL); } } switch (get_remote_arch()) { case RA_VISTA: case RA_SAMBA: case RA_CIFSFS: case RA_OSX: break; default: set_remote_arch(RA_VISTA); break; } fstr_sprintf(remote_proto, "SMB%X_%02X", (dialect >> 8) & 0xFF, dialect & 0xFF); reload_services(req->sconn, conn_snum_used, true); DEBUG(3,("Selected protocol %s\n", remote_proto)); in_preauth = smb2_negotiate_context_find(&in_c, SMB2_PREAUTH_INTEGRITY_CAPABILITIES); if (protocol >= PROTOCOL_SMB3_10 && in_preauth == NULL) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } in_cipher = smb2_negotiate_context_find(&in_c, SMB2_ENCRYPTION_CAPABILITIES); /* negprot_spnego() returns a the server guid in the first 16 bytes */ negprot_spnego_blob = negprot_spnego(req, xconn); if (negprot_spnego_blob.data == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } if (negprot_spnego_blob.length < 16) { return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR); } security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; /* * We use xconn->smb1.signing_state as that's already present * and used lpcfg_server_signing_allowed() to get the correct * defaults, e.g. signing_required for an ad_dc. */ signing_required = smb_signing_is_mandatory(xconn->smb1.signing_state); if (signing_required) { security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; } capabilities = 0; if (lp_host_msdfs()) { capabilities |= SMB2_CAP_DFS; } if (protocol >= PROTOCOL_SMB2_10 && lp_smb2_leases() && lp_oplocks(GLOBAL_SECTION_SNUM) && !lp_kernel_oplocks(GLOBAL_SECTION_SNUM)) { capabilities |= SMB2_CAP_LEASING; } if ((protocol >= PROTOCOL_SMB2_24) && (lp_smb_encrypt(-1) != SMB_SIGNING_OFF) && (in_capabilities & SMB2_CAP_ENCRYPTION)) { capabilities |= SMB2_CAP_ENCRYPTION; } /* * 0x10000 (65536) is the maximum allowed message size * for SMB 2.0 */ max_limit = 0x10000; if (protocol >= PROTOCOL_SMB2_10) { int p = 0; if (tsocket_address_is_inet(req->sconn->local_address, "ip")) { p = tsocket_address_inet_port(req->sconn->local_address); } /* largeMTU is not supported over NBT (tcp port 139) */ if (p != NBT_SMB_PORT) { capabilities |= SMB2_CAP_LARGE_MTU; xconn->smb2.credits.multicredit = true; /* * We allow up to almost 16MB. * * The maximum PDU size is 0xFFFFFF (16776960) * and we need some space for the header. */ max_limit = 0xFFFF00; } } /* * the defaults are 8MB, but we'll limit this to max_limit based on * the dialect (64kb for SMB 2.0, 8MB for SMB >= 2.1 with LargeMTU) * * user configured values exceeding the limits will be overwritten, * only smaller values will be accepted */ max_trans = MIN(max_limit, lp_smb2_max_trans()); max_read = MIN(max_limit, lp_smb2_max_read()); max_write = MIN(max_limit, lp_smb2_max_write()); if (in_preauth != NULL) { size_t needed = 4; uint16_t hash_count; uint16_t salt_length; uint16_t selected_preauth = 0; const uint8_t *p; uint8_t buf[38]; DATA_BLOB b; size_t i; if (in_preauth->data.length < needed) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } hash_count = SVAL(in_preauth->data.data, 0); salt_length = SVAL(in_preauth->data.data, 2); if (hash_count == 0) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } p = in_preauth->data.data + needed; needed += hash_count * 2; needed += salt_length; if (in_preauth->data.length < needed) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } for (i=0; i < hash_count; i++) { uint16_t v; v = SVAL(p, 0); p += 2; if (v == SMB2_PREAUTH_INTEGRITY_SHA512) { selected_preauth = v; break; } } if (selected_preauth == 0) { return smbd_smb2_request_error(req, NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP); } SSVAL(buf, 0, 1); /* HashAlgorithmCount */ SSVAL(buf, 2, 32); /* SaltLength */ SSVAL(buf, 4, selected_preauth); generate_random_buffer(buf + 6, 32); b = data_blob_const(buf, sizeof(buf)); status = smb2_negotiate_context_add(req, &out_c, SMB2_PREAUTH_INTEGRITY_CAPABILITIES, b); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } req->preauth = &req->xconn->smb2.preauth; } if (in_cipher != NULL) { size_t needed = 2; uint16_t cipher_count; const uint8_t *p; uint8_t buf[4]; DATA_BLOB b; size_t i; bool aes_128_ccm_supported = false; bool aes_128_gcm_supported = false; capabilities &= ~SMB2_CAP_ENCRYPTION; if (in_cipher->data.length < needed) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } cipher_count = SVAL(in_cipher->data.data, 0); if (cipher_count == 0) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } p = in_cipher->data.data + needed; needed += cipher_count * 2; if (in_cipher->data.length < needed) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } for (i=0; i < cipher_count; i++) { uint16_t v; v = SVAL(p, 0); p += 2; if (v == SMB2_ENCRYPTION_AES128_GCM) { aes_128_gcm_supported = true; } if (v == SMB2_ENCRYPTION_AES128_CCM) { aes_128_ccm_supported = true; } } /* * For now we preferr CCM because our implementation * is faster than GCM, see bug #11451. */ if (aes_128_ccm_supported) { xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM; } else if (aes_128_gcm_supported) { xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_GCM; } SSVAL(buf, 0, 1); /* ChiperCount */ SSVAL(buf, 2, xconn->smb2.server.cipher); b = data_blob_const(buf, sizeof(buf)); status = smb2_negotiate_context_add(req, &out_c, SMB2_ENCRYPTION_CAPABILITIES, b); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } } if (capabilities & SMB2_CAP_ENCRYPTION) { xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM; } if (protocol >= PROTOCOL_SMB2_22 && xconn->client->server_multi_channel_enabled) { if (in_capabilities & SMB2_CAP_MULTI_CHANNEL) { capabilities |= SMB2_CAP_MULTI_CHANNEL; } } security_offset = SMB2_HDR_BODY + 0x40; #if 1 /* Try SPNEGO auth... */ security_buffer = data_blob_const(negprot_spnego_blob.data + 16, negprot_spnego_blob.length - 16); #else /* for now we want raw NTLMSSP */ security_buffer = data_blob_const(NULL, 0); #endif if (out_c.num_contexts != 0) { status = smb2_negotiate_context_push(req, &out_negotiate_context_blob, out_c); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } } if (out_negotiate_context_blob.length != 0) { static const uint8_t zeros[8]; size_t pad = 0; size_t ofs; outdyn = data_blob_dup_talloc(req, security_buffer); if (outdyn.length != security_buffer.length) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } ofs = security_offset + security_buffer.length; if ((ofs % 8) != 0) { pad = 8 - (ofs % 8); } ofs += pad; ok = data_blob_append(req, &outdyn, zeros, pad); if (!ok) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } ok = data_blob_append(req, &outdyn, out_negotiate_context_blob.data, out_negotiate_context_blob.length); if (!ok) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } out_negotiate_context_offset = ofs; out_negotiate_context_count = out_c.num_contexts; } else { outdyn = security_buffer; } out_guid_blob = data_blob_const(negprot_spnego_blob.data, 16); status = GUID_from_ndr_blob(&out_guid_blob, &out_guid); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } outbody = smbd_smb2_generate_outbody(req, 0x40); if (outbody.data == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } SSVAL(outbody.data, 0x00, 0x40 + 1); /* struct size */ SSVAL(outbody.data, 0x02, security_mode); /* security mode */ SSVAL(outbody.data, 0x04, dialect); /* dialect revision */ SSVAL(outbody.data, 0x06, out_negotiate_context_count); /* reserved/NegotiateContextCount */ memcpy(outbody.data + 0x08, out_guid_blob.data, 16); /* server guid */ SIVAL(outbody.data, 0x18, capabilities); /* capabilities */ SIVAL(outbody.data, 0x1C, max_trans); /* max transact size */ SIVAL(outbody.data, 0x20, max_read); /* max read size */ SIVAL(outbody.data, 0x24, max_write); /* max write size */ SBVAL(outbody.data, 0x28, now); /* system time */ SBVAL(outbody.data, 0x30, 0); /* server start time */ SSVAL(outbody.data, 0x38, security_offset); /* security buffer offset */ SSVAL(outbody.data, 0x3A, security_buffer.length); /* security buffer length */ SIVAL(outbody.data, 0x3C, out_negotiate_context_offset); /* reserved/NegotiateContextOffset */ req->sconn->using_smb2 = true; if (dialect != SMB2_DIALECT_REVISION_2FF) { struct smbXsrv_client_global0 *global0 = NULL; status = smbXsrv_connection_init_tables(xconn, protocol); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } xconn->smb2.client.capabilities = in_capabilities; xconn->smb2.client.security_mode = in_security_mode; xconn->smb2.client.guid = in_guid; xconn->smb2.client.num_dialects = dialect_count; xconn->smb2.client.dialects = talloc_array(xconn, uint16_t, dialect_count); if (xconn->smb2.client.dialects == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } for (c=0; c < dialect_count; c++) { xconn->smb2.client.dialects[c] = SVAL(indyn, c*2); } xconn->smb2.server.capabilities = capabilities; xconn->smb2.server.security_mode = security_mode; xconn->smb2.server.guid = out_guid; xconn->smb2.server.dialect = dialect; xconn->smb2.server.max_trans = max_trans; xconn->smb2.server.max_read = max_read; xconn->smb2.server.max_write = max_write; if (xconn->protocol < PROTOCOL_SMB2_10) { /* * SMB2_02 doesn't support client guids */ return smbd_smb2_request_done(req, outbody, &outdyn); } if (!xconn->client->server_multi_channel_enabled) { /* * Only deal with the client guid database * if multi-channel is enabled. */ return smbd_smb2_request_done(req, outbody, &outdyn); } if (xconn->smb2.client.guid_verified) { /* * The connection was passed from another * smbd process. */ return smbd_smb2_request_done(req, outbody, &outdyn); } status = smb2srv_client_lookup_global(xconn->client, xconn->smb2.client.guid, req, &global0); /* * TODO: check for races... */ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECTID_NOT_FOUND)) { /* * This stores the new client information in * smbXsrv_client_global.tdb */ xconn->client->global->client_guid = xconn->smb2.client.guid; status = smbXsrv_client_update(xconn->client); if (!NT_STATUS_IS_OK(status)) { return status; } xconn->smb2.client.guid_verified = true; } else if (NT_STATUS_IS_OK(status)) { status = smb2srv_client_connection_pass(req, global0); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } smbd_server_connection_terminate(xconn, "passed connection"); return NT_STATUS_OBJECTID_EXISTS; } else { return smbd_smb2_request_error(req, status); } } return smbd_smb2_request_done(req, outbody, &outdyn); }
NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) { NTSTATUS status; const uint8_t *inbody; const uint8_t *indyn = NULL; DATA_BLOB outbody; DATA_BLOB outdyn; DATA_BLOB negprot_spnego_blob; uint16_t security_offset; DATA_BLOB security_buffer; size_t expected_dyn_size = 0; size_t c; uint16_t security_mode; uint16_t dialect_count; uint16_t in_security_mode; uint32_t in_capabilities; DATA_BLOB in_guid_blob; struct GUID in_guid; uint16_t dialect = 0; uint32_t capabilities; DATA_BLOB out_guid_blob; struct GUID out_guid; enum protocol_types protocol = PROTOCOL_NONE; uint32_t max_limit; uint32_t max_trans = lp_smb2_max_trans(); uint32_t max_read = lp_smb2_max_read(); uint32_t max_write = lp_smb2_max_write(); NTTIME now = timeval_to_nttime(&req->request_time); status = smbd_smb2_request_verify_sizes(req, 0x24); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } inbody = SMBD_SMB2_IN_BODY_PTR(req); dialect_count = SVAL(inbody, 0x02); in_security_mode = SVAL(inbody, 0x04); in_capabilities = IVAL(inbody, 0x08); in_guid_blob = data_blob_const(inbody + 0x0C, 16); if (dialect_count == 0) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } status = GUID_from_ndr_blob(&in_guid_blob, &in_guid); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } expected_dyn_size = dialect_count * 2; if (SMBD_SMB2_IN_DYN_LEN(req) < expected_dyn_size) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } indyn = SMBD_SMB2_IN_DYN_PTR(req); for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { if (lp_srv_maxprotocol() < PROTOCOL_SMB3_00) { break; } if (lp_srv_minprotocol() > PROTOCOL_SMB3_00) { break; } dialect = SVAL(indyn, c*2); if (dialect == SMB3_DIALECT_REVISION_300) { protocol = PROTOCOL_SMB3_00; break; } } for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { if (lp_srv_maxprotocol() < PROTOCOL_SMB2_24) { break; } if (lp_srv_minprotocol() > PROTOCOL_SMB2_24) { break; } dialect = SVAL(indyn, c*2); if (dialect == SMB2_DIALECT_REVISION_224) { protocol = PROTOCOL_SMB2_24; break; } } for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { if (lp_srv_maxprotocol() < PROTOCOL_SMB2_22) { break; } if (lp_srv_minprotocol() > PROTOCOL_SMB2_22) { break; } dialect = SVAL(indyn, c*2); if (dialect == SMB2_DIALECT_REVISION_222) { protocol = PROTOCOL_SMB2_22; break; } } for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { if (lp_srv_maxprotocol() < PROTOCOL_SMB2_10) { break; } if (lp_srv_minprotocol() > PROTOCOL_SMB2_10) { break; } dialect = SVAL(indyn, c*2); if (dialect == SMB2_DIALECT_REVISION_210) { protocol = PROTOCOL_SMB2_10; break; } } for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { if (lp_srv_maxprotocol() < PROTOCOL_SMB2_02) { break; } if (lp_srv_minprotocol() > PROTOCOL_SMB2_02) { break; } dialect = SVAL(indyn, c*2); if (dialect == SMB2_DIALECT_REVISION_202) { protocol = PROTOCOL_SMB2_02; break; } } for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { if (lp_srv_maxprotocol() < PROTOCOL_SMB2_10) { break; } dialect = SVAL(indyn, c*2); if (dialect == SMB2_DIALECT_REVISION_2FF) { if (req->sconn->smb2.negprot_2ff) { req->sconn->smb2.negprot_2ff = false; protocol = PROTOCOL_SMB2_10; break; } } } if (protocol == PROTOCOL_NONE) { return smbd_smb2_request_error(req, NT_STATUS_NOT_SUPPORTED); } if (get_remote_arch() != RA_SAMBA) { set_remote_arch(RA_VISTA); } fstr_sprintf(remote_proto, "SMB%X_%02X", (dialect >> 8) & 0xFF, dialect & 0xFF); reload_services(req->sconn, conn_snum_used, true); DEBUG(3,("Selected protocol %s\n", remote_proto)); /* negprot_spnego() returns a the server guid in the first 16 bytes */ negprot_spnego_blob = negprot_spnego(req, req->sconn); if (negprot_spnego_blob.data == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } if (negprot_spnego_blob.length < 16) { return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR); } security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; if (lp_server_signing() == SMB_SIGNING_REQUIRED) { security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; } capabilities = 0; if (lp_host_msdfs()) { capabilities |= SMB2_CAP_DFS; } if ((protocol >= PROTOCOL_SMB2_24) && (lp_smb_encrypt(-1) != SMB_SIGNING_OFF)) { if (in_capabilities & SMB2_CAP_ENCRYPTION) { capabilities |= SMB2_CAP_ENCRYPTION; } } /* * 0x10000 (65536) is the maximum allowed message size * for SMB 2.0 */ max_limit = 0x10000; if (protocol >= PROTOCOL_SMB2_10) { int p = 0; if (tsocket_address_is_inet(req->sconn->local_address, "ip")) { p = tsocket_address_inet_port(req->sconn->local_address); } /* largeMTU is not supported over NBT (tcp port 139) */ if (p != NBT_SMB_PORT) { capabilities |= SMB2_CAP_LARGE_MTU; req->sconn->smb2.supports_multicredit = true; /* SMB >= 2.1 has 1 MB of allowed size */ max_limit = 0x100000; /* 1MB */ } } /* * the defaults are 1MB, but we'll limit this to max_limit based on * the dialect (64kb for SMB2.0, 1MB for SMB2.1 with LargeMTU) * * user configured values exceeding the limits will be overwritten, * only smaller values will be accepted */ max_trans = MIN(max_limit, lp_smb2_max_trans()); max_read = MIN(max_limit, lp_smb2_max_read()); max_write = MIN(max_limit, lp_smb2_max_write()); security_offset = SMB2_HDR_BODY + 0x40; #if 1 /* Try SPNEGO auth... */ security_buffer = data_blob_const(negprot_spnego_blob.data + 16, negprot_spnego_blob.length - 16); #else /* for now we want raw NTLMSSP */ security_buffer = data_blob_const(NULL, 0); #endif out_guid_blob = data_blob_const(negprot_spnego_blob.data, 16); status = GUID_from_ndr_blob(&out_guid_blob, &out_guid); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } outbody = data_blob_talloc(req->out.vector, NULL, 0x40); if (outbody.data == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } SSVAL(outbody.data, 0x00, 0x40 + 1); /* struct size */ SSVAL(outbody.data, 0x02, security_mode); /* security mode */ SSVAL(outbody.data, 0x04, dialect); /* dialect revision */ SSVAL(outbody.data, 0x06, 0); /* reserved */ memcpy(outbody.data + 0x08, out_guid_blob.data, 16); /* server guid */ SIVAL(outbody.data, 0x18, capabilities); /* capabilities */ SIVAL(outbody.data, 0x1C, max_trans); /* max transact size */ SIVAL(outbody.data, 0x20, max_read); /* max read size */ SIVAL(outbody.data, 0x24, max_write); /* max write size */ SBVAL(outbody.data, 0x28, now); /* system time */ SBVAL(outbody.data, 0x30, 0); /* server start time */ SSVAL(outbody.data, 0x38, security_offset); /* security buffer offset */ SSVAL(outbody.data, 0x3A, security_buffer.length); /* security buffer length */ SIVAL(outbody.data, 0x3C, 0); /* reserved */ outdyn = security_buffer; req->sconn->using_smb2 = true; if (dialect != SMB2_DIALECT_REVISION_2FF) { struct smbXsrv_connection *conn = req->sconn->conn; status = smbXsrv_connection_init_tables(conn, protocol); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } conn->smb2.client.capabilities = in_capabilities; conn->smb2.client.security_mode = in_security_mode; conn->smb2.client.guid = in_guid; conn->smb2.client.num_dialects = dialect_count; conn->smb2.client.dialects = talloc_array(conn, uint16_t, dialect_count); if (conn->smb2.client.dialects == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } for (c=0; c < dialect_count; c++) { conn->smb2.client.dialects[c] = SVAL(indyn, c*2); } conn->smb2.server.capabilities = capabilities; conn->smb2.server.security_mode = security_mode; conn->smb2.server.guid = out_guid; conn->smb2.server.dialect = dialect; conn->smb2.server.max_trans = max_trans; conn->smb2.server.max_read = max_read; conn->smb2.server.max_write = max_write; req->sconn->smb2.max_trans = max_trans; req->sconn->smb2.max_read = max_read; req->sconn->smb2.max_write = max_write; } return smbd_smb2_request_done(req, outbody, &outdyn); }
/** build a GUID from a string */ _PUBLIC_ NTSTATUS GUID_from_data_blob(const DATA_BLOB *s, struct GUID *guid) { NTSTATUS status = NT_STATUS_INVALID_PARAMETER; uint32_t time_low; uint32_t time_mid, time_hi_and_version; uint32_t clock_seq[2]; uint32_t node[6]; uint8_t buf16[16]; DATA_BLOB blob16 = data_blob_const(buf16, sizeof(buf16)); int i; if (s->data == NULL) { return NT_STATUS_INVALID_PARAMETER; } if (s->length == 36) { TALLOC_CTX *mem_ctx; const char *string; mem_ctx = talloc_new(NULL); NT_STATUS_HAVE_NO_MEMORY(mem_ctx); string = talloc_strndup(mem_ctx, (const char *)s->data, s->length); NT_STATUS_HAVE_NO_MEMORY(string); if (11 == sscanf(string, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", &time_low, &time_mid, &time_hi_and_version, &clock_seq[0], &clock_seq[1], &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { status = NT_STATUS_OK; } talloc_free(mem_ctx); } else if (s->length == 38) { TALLOC_CTX *mem_ctx; const char *string; mem_ctx = talloc_new(NULL); NT_STATUS_HAVE_NO_MEMORY(mem_ctx); string = talloc_strndup(mem_ctx, (const char *)s->data, s->length); NT_STATUS_HAVE_NO_MEMORY(string); if (11 == sscanf((const char *)s->data, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", &time_low, &time_mid, &time_hi_and_version, &clock_seq[0], &clock_seq[1], &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { status = NT_STATUS_OK; } talloc_free(mem_ctx); } else if (s->length == 32) { size_t rlen = strhex_to_str((char *)blob16.data, blob16.length, (const char *)s->data, s->length); if (rlen == blob16.length) { /* goto the ndr_pull_struct_blob() path */ status = NT_STATUS_OK; s = &blob16; } } if (s->length == 16) { return GUID_from_ndr_blob(s, guid); } if (!NT_STATUS_IS_OK(status)) { return status; } guid->time_low = time_low; guid->time_mid = time_mid; guid->time_hi_and_version = time_hi_and_version; guid->clock_seq[0] = clock_seq[0]; guid->clock_seq[1] = clock_seq[1]; for (i=0;i<6;i++) { guid->node[i] = node[i]; } return NT_STATUS_OK; }