s3: smbd: Create and use a common function for generating a fileid - create_clock_iti...
authorJeremy Allison <jra@samba.org>
Wed, 5 Jan 2022 19:40:46 +0000 (11:40 -0800)
committerJeremy Allison <jra@samba.org>
Sat, 8 Jan 2022 06:35:22 +0000 (06:35 +0000)
This first gets the clock_gettime_mono() value, converts to an NTTIME (as
this is what is stored in the dos attribute EA), then mixes in 8 bits of
randomness shifted up by 55 bits to cope with poor resolution clocks to
avoid duplicate inodes.

Using 8 bits of randomness on top of an NTTIME gives us around 114
years headroom. We can now guarentee returning a itime-based
fileid in a normal share (storing dos attributes in an EA).

Remove knownfail.d/fileid-unique

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14928

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Christof Schmitt <cs@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Sat Jan  8 06:35:22 UTC 2022 on sn-devel-184

selftest/knownfail.d/fileid-unique [deleted file]
source3/include/proto.h
source3/lib/system.c
source3/smbd/open.c

diff --git a/selftest/knownfail.d/fileid-unique b/selftest/knownfail.d/fileid-unique
deleted file mode 100644 (file)
index a29c4a0..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba3.smb2.fileid_unique.fileid_unique\(fileserver\)
-^samba3.smb2.fileid_unique.fileid_unique-dir\(fileserver\)
index 6154b1ab26d452c17ff4a35a0c48c0c7cc09d55c..dba728b3d8634b858b7e9a5e9171ada6e6699372 100644 (file)
@@ -175,6 +175,7 @@ void update_stat_ex_create_time(struct stat_ex *dst, struct timespec create_time
 void update_stat_ex_file_id(struct stat_ex *dst, uint64_t file_id);
 void update_stat_ex_from_saved_stat(struct stat_ex *dst,
                                    const struct stat_ex *src);
+void create_clock_itime(struct stat_ex *dst);
 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
             bool fake_dir_create_times);
 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf,
index 671fc2760a02df446e7daafe06bd4137c62dd19f..0eb3d8564260473e860c1c65b0d2c2cf163d5e6b 100644 (file)
@@ -310,6 +310,58 @@ void init_stat_ex_from_stat (struct stat_ex *dst,
        dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_FILE_ID;
 }
 
+/*******************************************************************
+ Create a clock-derived itime (imaginary) time. Used to generate
+ the fileid.
+********************************************************************/
+
+void create_clock_itime(struct stat_ex *dst)
+{
+       NTTIME tval;
+       struct timespec itime;
+       uint64_t mixin;
+       uint8_t rval;
+
+       /* Start with the system clock. */
+       clock_gettime_mono(&itime);
+
+       /* Convert to NTTIME. */
+       tval = unix_timespec_to_nt_time(itime);
+
+       /*
+        * In case the system clock is poor granularity
+        * (happens on VM or docker images) then mix in
+        * 8 bits of randomness.
+        */
+       generate_random_buffer((unsigned char *)&rval, 1);
+       mixin = rval;
+
+       /*
+        * Shift up by 55 bits. This gives us approx 114 years
+        * of headroom.
+        */
+       mixin <<= 55;
+
+       /* And OR into the nttime. */
+       tval |= mixin;
+
+       /*
+        * Convert to a unix timespec, ignoring any
+        * constraints on seconds being higher than
+        * TIME_T_MAX or lower than TIME_T_MIN. These
+        * are only needed to allow unix display time functions
+        * to work correctly, and this is being used to
+        * generate a fileid. All we care about is the
+        * NTTIME being valid across all NTTIME ranges
+        * (which we carefully ensured above).
+        */
+
+       itime = nt_time_to_unix_timespec_raw(tval);
+
+       /* And set as a generated itime. */
+       update_stat_ex_itime(dst, itime);
+}
+
 /*******************************************************************
 A stat() wrapper.
 ********************************************************************/
index e3bb304292e20e04c3db8171018645162d87879b..cf5c620fe2120adbc589d0dc81dfe32e3d83fd51 100644 (file)
@@ -4129,13 +4129,13 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
         * If we created a file and it's not a stream, this is the point where
         * we set the itime (aka invented time) that get's stored in the DOS
         * attribute xattr. The value is going to be either what the filesystem
-        * provided or a copy of the creation date.
+        * provided or a generated itime value.
         *
         * Either way, we turn the itime into a File-ID, unless the filesystem
         * provided one (unlikely).
         */
        if (info == FILE_WAS_CREATED && !is_named_stream(smb_fname)) {
-               smb_fname->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME;
+               create_clock_itime(&smb_fname->st);
 
                if (lp_store_dos_attributes(SNUM(conn)) &&
                    smb_fname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)
@@ -4317,7 +4317,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                return NT_STATUS_NOT_A_DIRECTORY;
        }
 
-       smb_dname->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME;
+       create_clock_itime(&smb_dname->st);
 
        if (lp_store_dos_attributes(SNUM(conn))) {
                if (smb_dname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)