/* send a find request */ struct smb2_request *smb2_find_send(struct smb2_tree *tree, struct smb2_find *io) { struct smb2_request *req; NTSTATUS status; req = smb2_request_init_tree(tree, SMB2_OP_QUERY_DIRECTORY, 0x20, true, 0); if (req == NULL) return NULL; SCVAL(req->out.body, 0x02, io->in.level); SCVAL(req->out.body, 0x03, io->in.continue_flags); SIVAL(req->out.body, 0x04, io->in.file_index); smb2_push_handle(req->out.body+0x08, &io->in.file.handle); status = smb2_push_o16s16_string(&req->out, 0x18, io->in.pattern); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } SIVAL(req->out.body, 0x1C, io->in.max_response_size); smb2_transport_send(req); return req; }
/* send a create request */ struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create *io) { struct smb2_request *req; NTSTATUS status; DATA_BLOB blob = data_blob(NULL, 0); req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, True, 0); if (req == NULL) return NULL; SSVAL(req->out.body, 0x02, io->in.oplock_flags); SIVAL(req->out.body, 0x04, io->in.impersonation); SIVAL(req->out.body, 0x08, io->in.unknown3[0]); SIVAL(req->out.body, 0x0C, io->in.unknown3[1]); SIVAL(req->out.body, 0x10, io->in.unknown3[2]); SIVAL(req->out.body, 0x14, io->in.unknown3[3]); SIVAL(req->out.body, 0x18, io->in.access_mask); SIVAL(req->out.body, 0x1C, io->in.file_attr); SIVAL(req->out.body, 0x20, io->in.share_access); SIVAL(req->out.body, 0x24, io->in.open_disposition); SIVAL(req->out.body, 0x28, io->in.create_options); status = smb2_push_o16s16_string(&req->out, 0x2C, io->in.fname); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } if (io->in.eas.num_eas != 0) { DATA_BLOB b = data_blob_talloc(req, NULL, ea_list_size_chained(io->in.eas.num_eas, io->in.eas.eas)); ea_put_list_chained(b.data, io->in.eas.num_eas, io->in.eas.eas); status = smb2_create_blob_add(req, &blob, CREATE_TAG_EXTA, b, False); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } data_blob_free(&b); } /* an empty MxAc tag seems to be used to ask the server to return the maximum access mask allowed on the file */ status = smb2_create_blob_add(req, &blob, CREATE_TAG_MXAC, data_blob(NULL, 0), True); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } status = smb2_push_o32s32_blob(&req->out, 0x30, blob); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } smb2_transport_send(req); return req; }
/* Send a Lease Break Acknowledgement */ struct smb2_request *smb2_lease_break_ack_send(struct smb2_tree *tree, struct smb2_lease_break_ack *io) { struct smb2_request *req; req = smb2_request_init_tree(tree, SMB2_OP_BREAK, 0x24, false, 0); if (req == NULL) return NULL; SIVAL(req->out.body, 0x02, io->in.reserved); SIVAL(req->out.body, 0x04, io->in.lease.lease_flags); memcpy(req->out.body+0x8, &io->in.lease.lease_key, sizeof(struct smb2_lease_key)); SIVAL(req->out.body, 0x18, io->in.lease.lease_state); SBVAL(req->out.body, 0x1C, io->in.lease.lease_duration); smb2_transport_send(req); return req; }
/* send a read request */ struct smb2_request *smb2_read_send(struct smb2_tree *tree, struct smb2_read *io) { struct smb2_request *req; req = smb2_request_init_tree(tree, SMB2_OP_READ, 0x30, true, 0); if (req == NULL) return NULL; SCVAL(req->out.body, 0x02, 0); /* pad */ SCVAL(req->out.body, 0x03, 0); /* reserved */ SIVAL(req->out.body, 0x04, io->in.length); SBVAL(req->out.body, 0x08, io->in.offset); smb2_push_handle(req->out.body+0x10, &io->in.file.handle); SIVAL(req->out.body, 0x20, io->in.min_count); SIVAL(req->out.body, 0x24, io->in.channel); SIVAL(req->out.body, 0x28, io->in.remaining); SSVAL(req->out.body, 0x2C, io->in.channel_offset); SSVAL(req->out.body, 0x2E, io->in.channel_length); req->credit_charge = (MAX(io->in.length, 1) - 1)/ 65536 + 1; smb2_transport_send(req); return req; }
/* send a write request */ struct smb2_request *smb2_write_send(struct smb2_tree *tree, struct smb2_write *io) { NTSTATUS status; struct smb2_request *req; req = smb2_request_init_tree(tree, SMB2_OP_WRITE, 0x30, true, io->in.data.length); if (req == NULL) return NULL; status = smb2_push_o16s32_blob(&req->out, 0x02, io->in.data); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } SBVAL(req->out.body, 0x08, io->in.offset); smb2_push_handle(req->out.body+0x10, &io->in.file.handle); SBVAL(req->out.body, 0x20, io->in.unknown1); SBVAL(req->out.body, 0x28, io->in.unknown2); smb2_transport_send(req); return req; }
/* send a create request */ struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create *io) { struct smb2_request *req; NTSTATUS status; DATA_BLOB blob; struct smb2_create_blobs blobs; int i; ZERO_STRUCT(blobs); req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, true, 0); if (req == NULL) return NULL; SCVAL(req->out.body, 0x02, io->in.security_flags); SCVAL(req->out.body, 0x03, io->in.oplock_level); SIVAL(req->out.body, 0x04, io->in.impersonation_level); SBVAL(req->out.body, 0x08, io->in.create_flags); SBVAL(req->out.body, 0x10, io->in.reserved); SIVAL(req->out.body, 0x18, io->in.desired_access); SIVAL(req->out.body, 0x1C, io->in.file_attributes); SIVAL(req->out.body, 0x20, io->in.share_access); SIVAL(req->out.body, 0x24, io->in.create_disposition); SIVAL(req->out.body, 0x28, io->in.create_options); status = smb2_push_o16s16_string(&req->out, 0x2C, io->in.fname); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } /* now add all the optional blobs */ if (io->in.eas.num_eas != 0) { DATA_BLOB b = data_blob_talloc(req, NULL, ea_list_size_chained(io->in.eas.num_eas, io->in.eas.eas, 4)); ea_put_list_chained(b.data, io->in.eas.num_eas, io->in.eas.eas, 4); status = smb2_create_blob_add(req, &blobs, SMB2_CREATE_TAG_EXTA, b); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } data_blob_free(&b); } /* an empty MxAc tag seems to be used to ask the server to return the maximum access mask allowed on the file */ if (io->in.query_maximal_access) { /* TODO: MS-SMB2 2.2.13.2.5 says this can contain a timestamp? What to do with that if it doesn't match? */ status = smb2_create_blob_add(req, &blobs, SMB2_CREATE_TAG_MXAC, data_blob(NULL, 0)); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } } if (io->in.alloc_size != 0) { uint8_t data[8]; SBVAL(data, 0, io->in.alloc_size); status = smb2_create_blob_add(req, &blobs, SMB2_CREATE_TAG_ALSI, data_blob_const(data, 8)); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } } if (io->in.durable_open) { status = smb2_create_blob_add(req, &blobs, SMB2_CREATE_TAG_DHNQ, data_blob_talloc_zero(req, 16)); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } } if (io->in.durable_handle) { uint8_t data[16]; smb2_push_handle(data, io->in.durable_handle); status = smb2_create_blob_add(req, &blobs, SMB2_CREATE_TAG_DHNC, data_blob_const(data, 16)); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } } if (io->in.timewarp) { uint8_t data[8]; SBVAL(data, 0, io->in.timewarp); status = smb2_create_blob_add(req, &blobs, SMB2_CREATE_TAG_TWRP, data_blob_const(data, 8)); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } } if (io->in.sec_desc) { enum ndr_err_code ndr_err; DATA_BLOB sd_blob; ndr_err = ndr_push_struct_blob(&sd_blob, req, io->in.sec_desc, (ndr_push_flags_fn_t)ndr_push_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(req); return NULL; } status = smb2_create_blob_add(req, &blobs, SMB2_CREATE_TAG_SECD, sd_blob); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } } if (io->in.query_on_disk_id) { status = smb2_create_blob_add(req, &blobs, SMB2_CREATE_TAG_QFID, data_blob(NULL, 0)); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } } if (io->in.lease_request) { uint8_t data[32]; memcpy(&data[0], &io->in.lease_request->lease_key, 16); SIVAL(data, 16, io->in.lease_request->lease_state); SIVAL(data, 20, io->in.lease_request->lease_flags); SBVAL(data, 24, io->in.lease_request->lease_duration); status = smb2_create_blob_add(req, &blobs, SMB2_CREATE_TAG_RQLS, data_blob_const(data, 32)); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } } /* and any custom blobs */ for (i=0;i<io->in.blobs.num_blobs;i++) { status = smb2_create_blob_add(req, &blobs, io->in.blobs.blobs[i].tag, io->in.blobs.blobs[i].data); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } } status = smb2_create_blob_push(req, &blob, blobs); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } status = smb2_push_o32s32_blob(&req->out, 0x30, blob); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } data_blob_free(&blob); smb2_transport_send(req); return req; }