s3:smb2_break: encrypt OPLOCK BREAK notifications
authorStefan Metzmacher <metze@samba.org>
Wed, 22 Aug 2012 08:33:07 +0000 (10:33 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 23 Aug 2012 08:01:14 +0000 (10:01 +0200)
metze

Autobuild-User(master): Stefan Metzmacher <metze@samba.org>
Autobuild-Date(master): Thu Aug 23 10:01:14 CEST 2012 on sn-devel-104

source3/smbd/globals.h
source3/smbd/smb2_break.c
source3/smbd/smb2_server.c

index b024fb35f842c96a7529ca9fd7584016fc21a7cc..6af17a47c3efbb8f3b08b13f1ac16660c6224b30 100644 (file)
@@ -235,8 +235,9 @@ NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
        smbd_smb2_request_done_ex(req, NT_STATUS_OK, body, dyn, __location__)
 
 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
-                                    uint64_t file_id_persistent,
-                                    uint64_t file_id_volatile,
+                                    struct smbXsrv_session *session,
+                                    struct smbXsrv_tcon *tcon,
+                                    struct smbXsrv_open *op,
                                     uint8_t oplock_level);
 
 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
index 8143b8b97637fd818c34d33efdff467760e6e241..8db9e6ddeceac4ca4e9d46afcb38377903db3eb1 100644 (file)
@@ -235,6 +235,26 @@ void send_break_message_smb2(files_struct *fsp, int level)
                                SMB2_OPLOCK_LEVEL_II :
                                SMB2_OPLOCK_LEVEL_NONE;
        NTSTATUS status;
+       struct smbXsrv_session *session = NULL;
+       struct timeval tv = timeval_current();
+       NTTIME now = timeval_to_nttime(&tv);
+
+       status = smb2srv_session_lookup(fsp->conn->sconn->conn,
+                                       fsp->vuid,
+                                       now,
+                                       &session);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED) ||
+           (session == NULL))
+       {
+
+               DEBUG(10,("send_break_message_smb2: skip oplock break "
+                       "for file %s, %s, smb2 level %u session %llu not found\n",
+                       fsp_str_dbg(fsp),
+                       fsp_fnum_dbg(fsp),
+                       (unsigned int)smb2_oplock_level,
+                       (unsigned long long)fsp->vuid));
+               return;
+       }
 
        DEBUG(10,("send_break_message_smb2: sending oplock break "
                "for file %s, %s, smb2 level %u\n",
@@ -243,9 +263,10 @@ void send_break_message_smb2(files_struct *fsp, int level)
                (unsigned int)smb2_oplock_level ));
 
        status = smbd_smb2_send_oplock_break(fsp->conn->sconn,
-                                       fsp->op->global->open_persistent_id,
-                                       fsp->op->global->open_volatile_id,
-                                       smb2_oplock_level);
+                                            session,
+                                            fsp->conn->tcon,
+                                            fsp->op,
+                                            smb2_oplock_level);
        if (!NT_STATUS_IS_OK(status)) {
                smbd_server_connection_terminate(fsp->conn->sconn,
                                 nt_errstr(status));
index ad5b70e928ecc2b8823409fb7a4510c48afd8b1a..be7997febfb919b9bacfd3705f4d10765bbafa2f 100644 (file)
@@ -2694,21 +2694,35 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
 
 struct smbd_smb2_send_oplock_break_state {
        struct smbd_server_connection *sconn;
-       uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
-       struct iovec vector;
+       uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x18];
+       struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
 };
 
 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
 
 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
-                                    uint64_t file_id_persistent,
-                                    uint64_t file_id_volatile,
+                                    struct smbXsrv_session *session,
+                                    struct smbXsrv_tcon *tcon,
+                                    struct smbXsrv_open *op,
                                     uint8_t oplock_level)
 {
        struct smbd_smb2_send_oplock_break_state *state;
+       struct smbXsrv_connection *conn = sconn->conn;
        struct tevent_req *subreq;
+       uint8_t *tf;
+       size_t tf_len;
        uint8_t *hdr;
        uint8_t *body;
+       size_t body_len;
+       uint8_t *dyn;
+       size_t dyn_len;
+       bool do_encryption = session->global->encryption_required;
+       uint64_t nonce_high = 0;
+       uint64_t nonce_low = 0;
+
+       if (tcon->global->encryption_required) {
+               do_encryption = true;
+       }
 
        state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
        if (state == NULL) {
@@ -2716,12 +2730,29 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
        }
        state->sconn = sconn;
 
-       state->vector.iov_base = (void *)state->buf;
-       state->vector.iov_len = sizeof(state->buf);
-
-       _smb2_setlen(state->buf, sizeof(state->buf) - 4);
-       hdr = state->buf + 4;
+       tf = state->buf + NBT_HDR_SIZE;
+       tf_len = SMB2_TF_HDR_SIZE;
+       hdr = tf + tf_len;
        body = hdr + SMB2_HDR_BODY;
+       body_len = 0x18;
+       dyn = body + body_len;
+       dyn_len = 0;
+
+       if (do_encryption) {
+               nonce_high = session->nonce_high;
+               nonce_low = session->nonce_low;
+
+               session->nonce_low += 1;
+               if (session->nonce_low == 0) {
+                       session->nonce_low += 1;
+                       session->nonce_high += 1;
+               }
+       }
+
+       SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
+       SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
+       SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
+       SBVAL(tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
 
        SIVAL(hdr, 0,                           SMB2_MAGIC);
        SSVAL(hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
@@ -2737,19 +2768,55 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
        SBVAL(hdr, SMB2_HDR_SESSION_ID,         0);
        memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
 
-       SSVAL(body, 0x00, 0x18);
+       SSVAL(body, 0x00, body_len);
 
        SCVAL(body, 0x02, oplock_level);
        SCVAL(body, 0x03, 0);           /* reserved */
        SIVAL(body, 0x04, 0);           /* reserved */
-       SBVAL(body, 0x08, file_id_persistent);
-       SBVAL(body, 0x10, file_id_volatile);
+       SBVAL(body, 0x08, op->global->open_persistent_id);
+       SBVAL(body, 0x10, op->global->open_volatile_id);
+
+       state->vector[0].iov_base = (void *)state->buf;
+       state->vector[0].iov_len = NBT_HDR_SIZE;
+
+       if (do_encryption) {
+               state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base   = tf;
+               state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len    = tf_len;
+       } else {
+               state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base   = NULL;
+               state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len    = 0;
+       }
+
+       state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base  = hdr;
+       state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len   = SMB2_HDR_BODY;
+
+       state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
+       state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len  = body_len;
+
+       state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base  = dyn;
+       state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len   = dyn_len;
+
+       smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
+
+       if (do_encryption) {
+               NTSTATUS status;
+               DATA_BLOB encryption_key = session->global->encryption_key;
+
+               status = smb2_signing_encrypt_pdu(encryption_key,
+                                       conn->protocol,
+                                       &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
+                                       SMBD_SMB2_NUM_IOV_PER_REQ);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
 
        subreq = tstream_writev_queue_send(state,
                                           sconn->ev_ctx,
                                           sconn->smb2.stream,
                                           sconn->smb2.send_queue,
-                                          &state->vector, 1);
+                                          state->vector,
+                                          ARRAY_SIZE(state->vector));
        if (subreq == NULL) {
                return NT_STATUS_NO_MEMORY;
        }