struct ntvfs_handle *smb2srv_pull_handle(struct smb2srv_request *req, const uint8_t *base, uint_t offset) { struct smbsrv_tcon *tcon; struct smbsrv_handle *handle; uint64_t hid; uint32_t tid; uint32_t pad; hid = BVAL(base, offset); tid = IVAL(base, offset + 8); pad = IVAL(base, offset + 12); if (pad != UINT32_MAX) { return NULL; } /* if it's the wildcard handle, don't waste time to search it... */ if (hid == UINT64_MAX && tid == UINT32_MAX) { return NULL; } /* * the handle can belong to a different tcon * as that TID in the SMB2 header says, but * the request should succeed nevertheless! * * because if this we put the 32 bit TID into the * 128 bit handle, so that we can extract the tcon from the * handle */ tcon = req->tcon; if (tid != req->tcon->tid) { tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time); if (!tcon) { return NULL; } } handle = smbsrv_smb2_handle_find(tcon, hid, req->request_time); if (!handle) { return NULL; } /* * as the smb2srv_tcon is a child object of the smb2srv_session * the handle belongs to the correct session! * * Note: no check is needed here for SMB2 */ /* * as the handle may have overwritten the tcon * we need to set it on the request so that the * correct ntvfs context will be used for the ntvfs_*() request */ req->tcon = tcon; return handle->ntvfs; }
static NTSTATUS smb2srv_reply(struct smb2srv_request *req) { uint16_t opcode; uint32_t tid; uint64_t uid; uint32_t flags; if (SVAL(req->in.hdr, SMB2_HDR_LENGTH) != SMB2_HDR_BODY) { smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 header length"); return NT_STATUS_INVALID_PARAMETER; } opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE); req->chain_offset = IVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND); req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID); tid = IVAL(req->in.hdr, SMB2_HDR_TID); uid = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID); flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS); if (opcode != SMB2_OP_CANCEL && req->smb_conn->highest_smb2_seqnum != 0 && req->seqnum <= req->smb_conn->highest_smb2_seqnum) { smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 sequence number"); return NT_STATUS_INVALID_PARAMETER; } if (opcode != SMB2_OP_CANCEL) { req->smb_conn->highest_smb2_seqnum = req->seqnum; } if (flags & SMB2_HDR_FLAG_CHAINED) { uid = req->chained_session_id; tid = req->chained_tree_id; } req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time); req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time); req->chained_session_id = uid; req->chained_tree_id = tid; errno = 0; /* supporting signing is mandatory in SMB2, and is per-packet. So we should check the signature on any incoming packet that is signed, and should give a signed reply to any signed request */ if (flags & SMB2_HDR_FLAG_SIGNED) { NTSTATUS status; if (!req->session) goto nosession; req->is_signed = true; status = smb2_check_signature(&req->in, req->session->session_info->session_key); if (!NT_STATUS_IS_OK(status)) { smb2srv_send_error(req, status); return NT_STATUS_OK; } } else if (req->session && req->session->smb2_signing.active) { /* we require signing and this request was not signed */ smb2srv_send_error(req, NT_STATUS_ACCESS_DENIED); return NT_STATUS_OK; } if (!NT_STATUS_IS_OK(req->chain_status)) { smb2srv_send_error(req, req->chain_status); return NT_STATUS_OK; } switch (opcode) { case SMB2_OP_NEGPROT: smb2srv_negprot_recv(req); return NT_STATUS_OK; case SMB2_OP_SESSSETUP: smb2srv_sesssetup_recv(req); return NT_STATUS_OK; case SMB2_OP_LOGOFF: if (!req->session) goto nosession; smb2srv_logoff_recv(req); return NT_STATUS_OK; case SMB2_OP_TCON: if (!req->session) goto nosession; smb2srv_tcon_recv(req); return NT_STATUS_OK; case SMB2_OP_TDIS: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_tdis_recv(req); return NT_STATUS_OK; case SMB2_OP_CREATE: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_create_recv(req); return NT_STATUS_OK; case SMB2_OP_CLOSE: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_close_recv(req); return NT_STATUS_OK; case SMB2_OP_FLUSH: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_flush_recv(req); return NT_STATUS_OK; case SMB2_OP_READ: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_read_recv(req); return NT_STATUS_OK; case SMB2_OP_WRITE: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_write_recv(req); return NT_STATUS_OK; case SMB2_OP_LOCK: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_lock_recv(req); return NT_STATUS_OK; case SMB2_OP_IOCTL: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_ioctl_recv(req); return NT_STATUS_OK; case SMB2_OP_CANCEL: smb2srv_cancel_recv(req); return NT_STATUS_OK; case SMB2_OP_KEEPALIVE: smb2srv_keepalive_recv(req); return NT_STATUS_OK; case SMB2_OP_FIND: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_find_recv(req); return NT_STATUS_OK; case SMB2_OP_NOTIFY: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_notify_recv(req); return NT_STATUS_OK; case SMB2_OP_GETINFO: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_getinfo_recv(req); return NT_STATUS_OK; case SMB2_OP_SETINFO: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_setinfo_recv(req); return NT_STATUS_OK; case SMB2_OP_BREAK: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_break_recv(req); return NT_STATUS_OK; } DEBUG(1,("Invalid SMB2 opcode: 0x%04X\n", opcode)); smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 opcode"); return NT_STATUS_OK; nosession: smb2srv_send_error(req, NT_STATUS_USER_SESSION_DELETED); return NT_STATUS_OK; notcon: smb2srv_send_error(req, NT_STATUS_NETWORK_NAME_DELETED); return NT_STATUS_OK; }