s3:smbd: try to make fsp->fh->gen_id as globally unique as possible
[ddiss/samba.git] / source3 / smbd / files.c
index fafb10d89964f6db5b4ecb580bf7008b76674a7c..0018ceed5e51cf0b45afa3606b5a78c9146704c6 100644 (file)
 #define FILE_HANDLE_OFFSET 0x1000
 
 /****************************************************************************
- Return a unique number identifying this fsp over the life of this pid.
+ Return a unique number identifying this fsp over the life of this pid,
+ and try to make it as globally unique as possible.
+ See bug #8995 for the details.
 ****************************************************************************/
 
 static unsigned long get_gen_count(struct smbd_server_connection *sconn)
 {
+       /*
+        * While fsp->fh->gen_id is 'unsigned long' currently
+        * (which might by 8 bytes),
+        * there's some oplock code which truncates it to
+        * uint32_t(using IVAL()).
+        */
+       if (sconn->file_gen_counter == 0) {
+               sconn->file_gen_counter = generate_random();
+       }
        sconn->file_gen_counter += 1;
+       if (sconn->file_gen_counter >= UINT32_MAX) {
+               sconn->file_gen_counter = 0;
+       }
        if (sconn->file_gen_counter == 0) {
                sconn->file_gen_counter += 1;
        }
@@ -284,6 +298,10 @@ files_struct *file_find_dif(struct smbd_server_connection *sconn,
        int count=0;
        files_struct *fsp;
 
+       if (gen_id == 0) {
+               return NULL;
+       }
+
        for (fsp=sconn->files; fsp; fsp=fsp->next,count++) {
                /* We can have a fsp->fh->fd == -1 here as it could be a stat open. */
                if (file_id_equal(&fsp->file_id, &id) &&
@@ -544,13 +562,53 @@ files_struct *file_fsp(struct smb_request *req, uint16 fid)
        fsp = file_fnum(req->sconn, fid);
        if (fsp != NULL) {
                req->chain_fsp = fsp;
-               if (req->smb2req != NULL) {
-                       req->smb2req->compat_chain_fsp = fsp;
-               }
        }
        return fsp;
 }
 
+struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req,
+                                  uint64_t persistent_id,
+                                  uint64_t volatile_id)
+{
+       struct files_struct *fsp;
+
+       if (smb2req->compat_chain_fsp != NULL) {
+               return smb2req->compat_chain_fsp;
+       }
+
+       if (persistent_id != volatile_id) {
+               return NULL;
+       }
+
+       if (volatile_id > UINT16_MAX) {
+               return NULL;
+       }
+
+       fsp = file_fnum(smb2req->sconn, (uint16_t)volatile_id);
+       if (fsp == NULL) {
+               return NULL;
+       }
+
+       if (smb2req->tcon == NULL) {
+               return NULL;
+       }
+
+       if (smb2req->tcon->compat_conn != fsp->conn) {
+               return NULL;
+       }
+
+       if (smb2req->session == NULL) {
+               return NULL;
+       }
+
+       if (smb2req->session->vuid != fsp->vuid) {
+               return NULL;
+       }
+
+       smb2req->compat_chain_fsp = fsp;
+       return fsp;
+}
+
 /****************************************************************************
  Duplicate the file handle part for a DOS or FCB open.
 ****************************************************************************/