void smb2srv_create_recv(struct smb2srv_request *req) { union smb_open *io; DATA_BLOB blob; int i; SMB2SRV_CHECK_BODY_SIZE(req, 0x38, true); SMB2SRV_TALLOC_IO_PTR(io, union smb_open); SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_create_send, NTVFS_ASYNC_STATE_MAY_ASYNC); ZERO_STRUCT(io->smb2.in); io->smb2.level = RAW_OPEN_SMB2; io->smb2.in.security_flags = CVAL(req->in.body, 0x02); io->smb2.in.oplock_level = CVAL(req->in.body, 0x03); io->smb2.in.impersonation_level = IVAL(req->in.body, 0x04); io->smb2.in.create_flags = BVAL(req->in.body, 0x08); io->smb2.in.reserved = BVAL(req->in.body, 0x10); io->smb2.in.desired_access = IVAL(req->in.body, 0x18); io->smb2.in.file_attributes = IVAL(req->in.body, 0x1C); io->smb2.in.share_access = IVAL(req->in.body, 0x20); io->smb2.in.create_disposition = IVAL(req->in.body, 0x24); io->smb2.in.create_options = IVAL(req->in.body, 0x28); SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, io, req->in.body+0x2C, &io->smb2.in.fname)); SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req->in, io, req->in.body+0x30, &blob)); SMB2SRV_CHECK(smb2_create_blob_parse(io, blob, &io->smb2.in.blobs)); /* interpret the parsed tags that a server needs to respond to */ for (i=0;i<io->smb2.in.blobs.num_blobs;i++) { if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_EXTA) == 0) { SMB2SRV_CHECK(ea_pull_list_chained(&io->smb2.in.blobs.blobs[i].data, io, &io->smb2.in.eas.num_eas, &io->smb2.in.eas.eas)); } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_SECD) == 0) { enum ndr_err_code ndr_err; io->smb2.in.sec_desc = talloc(io, struct security_descriptor); if (io->smb2.in.sec_desc == NULL) { smb2srv_send_error(req, NT_STATUS_NO_MEMORY); return; } ndr_err = ndr_pull_struct_blob(&io->smb2.in.blobs.blobs[i].data, io, NULL, io->smb2.in.sec_desc, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { smb2srv_send_error(req, ndr_map_error2ntstatus(ndr_err)); return; } } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNQ) == 0) { io->smb2.in.durable_open = true; } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNC) == 0) { if (io->smb2.in.blobs.blobs[i].data.length != 16) { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } io->smb2.in.durable_handle = talloc(io, struct smb2_handle); if (io->smb2.in.durable_handle == NULL) { smb2srv_send_error(req, NT_STATUS_NO_MEMORY); return; } smb2_pull_handle(io->smb2.in.blobs.blobs[i].data.data, io->smb2.in.durable_handle); } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_ALSI) == 0) { if (io->smb2.in.blobs.blobs[i].data.length != 8) { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } io->smb2.in.alloc_size = BVAL(io->smb2.in.blobs.blobs[i].data.data, 0); } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) { io->smb2.in.query_maximal_access = true; } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_TWRP) == 0) { if (io->smb2.in.blobs.blobs[i].data.length != 8) { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } io->smb2.in.timewarp = BVAL(io->smb2.in.blobs.blobs[i].data.data, 0); } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) { io->smb2.in.query_on_disk_id = true; } } /* the VFS backend does not yet handle NULL filenames */ if (io->smb2.in.fname == NULL) { io->smb2.in.fname = ""; } SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, io)); }
/* recv a create reply */ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_create *io) { NTSTATUS status; DATA_BLOB blob; int i; if (!smb2_request_receive(req) || !smb2_request_is_ok(req)) { return smb2_request_destroy(req); } SMB2_CHECK_PACKET_RECV(req, 0x58, true); ZERO_STRUCT(io->out); io->out.oplock_level = CVAL(req->in.body, 0x02); io->out.reserved = CVAL(req->in.body, 0x03); io->out.create_action = IVAL(req->in.body, 0x04); io->out.create_time = smbcli_pull_nttime(req->in.body, 0x08); io->out.access_time = smbcli_pull_nttime(req->in.body, 0x10); io->out.write_time = smbcli_pull_nttime(req->in.body, 0x18); io->out.change_time = smbcli_pull_nttime(req->in.body, 0x20); io->out.alloc_size = BVAL(req->in.body, 0x28); io->out.size = BVAL(req->in.body, 0x30); io->out.file_attr = IVAL(req->in.body, 0x38); io->out.reserved2 = IVAL(req->in.body, 0x3C); smb2_pull_handle(req->in.body+0x40, &io->out.file.handle); status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x50, &blob); if (!NT_STATUS_IS_OK(status)) { smb2_request_destroy(req); return status; } status = smb2_create_blob_parse(mem_ctx, blob, &io->out.blobs); if (!NT_STATUS_IS_OK(status)) { smb2_request_destroy(req); return status; } /* pull out the parsed blobs */ for (i=0;i<io->out.blobs.num_blobs;i++) { if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) { /* TODO: this also contains a status field in first 4 bytes */ if (io->out.blobs.blobs[i].data.length != 8) { smb2_request_destroy(req); return NT_STATUS_INVALID_NETWORK_RESPONSE; } io->out.maximal_access = IVAL(io->out.blobs.blobs[i].data.data, 4); } if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) { if (io->out.blobs.blobs[i].data.length != 32) { smb2_request_destroy(req); return NT_STATUS_INVALID_NETWORK_RESPONSE; } memcpy(io->out.on_disk_id, io->out.blobs.blobs[i].data.data, 32); } if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_RQLS) == 0) { uint8_t *data; if (io->out.blobs.blobs[i].data.length != 32) { smb2_request_destroy(req); return NT_STATUS_INVALID_NETWORK_RESPONSE; } data = io->out.blobs.blobs[i].data.data; memcpy(&io->out.lease_response.lease_key, data, 16); io->out.lease_response.lease_state = IVAL(data, 16); io->out.lease_response.lease_flags = IVAL(data, 20); io->out.lease_response.lease_duration = BVAL(data, 24); } } data_blob_free(&blob); return smb2_request_destroy(req); }
static void smb2_transport_break_handler(struct tevent_req *subreq) { struct smb2_transport *transport = tevent_req_callback_data(subreq, struct smb2_transport); NTSTATUS status; uint8_t *hdr; uint8_t *body; uint16_t len = 0; bool lease; struct iovec *recv_iov = NULL; transport->break_subreq = NULL; status = smb2cli_req_recv(subreq, transport, &recv_iov, NULL, 0); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(recv_iov); smb2_transport_dead(transport, status); return; } /* * Setup the subreq to handle the * next incoming SMB2 Break. */ subreq = smb2cli_req_create(transport, transport->ev, transport->conn, SMB2_OP_BREAK, 0, /* additional_flags */ 0, /*clear_flags */ 0, /* timeout_msec */ 0, /* pid */ 0, /* tid */ NULL, /* session */ NULL, /* body */ 0, /* body_fixed */ NULL, /* dyn */ 0); /* dyn_len */ if (subreq != NULL) { smbXcli_req_set_pending(subreq); tevent_req_set_callback(subreq, smb2_transport_break_handler, transport); transport->break_subreq = subreq; } hdr = recv_iov[0].iov_base; body = recv_iov[1].iov_base; len = recv_iov[1].iov_len; if (recv_iov[1].iov_len >= 2) { len = CVAL(body, 0x00); if (len != recv_iov[1].iov_len) { len = recv_iov[1].iov_len; } } if (len == 24) { lease = false; } else if (len == 44) { lease = true; } else { DEBUG(1,("Discarding smb2 oplock reply of invalid size %u\n", (unsigned)len)); TALLOC_FREE(recv_iov); status = NT_STATUS_INVALID_NETWORK_RESPONSE; smb2_transport_dead(transport, status); return; } if (!lease && transport->oplock.handler) { struct smb2_handle h; uint8_t level; level = CVAL(body, 0x02); smb2_pull_handle(body+0x08, &h); TALLOC_FREE(recv_iov); transport->oplock.handler(transport, &h, level, transport->oplock.private_data); } else if (lease && transport->lease.handler) { struct smb2_lease_break lb; ZERO_STRUCT(lb); lb.break_flags = SVAL(body, 0x4); memcpy(&lb.current_lease.lease_key, body+0x8, sizeof(struct smb2_lease_key)); lb.current_lease.lease_state = SVAL(body, 0x18); lb.new_lease_state = SVAL(body, 0x1C); lb.break_reason = SVAL(body, 0x20); lb.access_mask_hint = SVAL(body, 0x24); lb.share_mask_hint = SVAL(body, 0x28); TALLOC_FREE(recv_iov); transport->lease.handler(transport, &lb, transport->lease.private_data); } else { DEBUG(5,("Got SMB2 %s break with no handler\n", lease ? "lease" : "oplock")); } TALLOC_FREE(recv_iov); }