Fix bug #7067 - Linux asynchronous IO (aio) can cause smbd to fail to respond to...
[ira/wip.git] / source3 / lib / system.c
index 6a4f5d54130658156bf366dc061c7b6c08583601..9c1da3a78bdcdf301883cc74fcdc6bfcb00a5834 100644 (file)
@@ -456,9 +456,10 @@ static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
  use the best approximation.
 ****************************************************************************/
 
-static void get_create_timespec(const struct stat *pst, struct stat_ex *dst)
+static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
+                                bool fake_dir_create_times)
 {
-       if (S_ISDIR(pst->st_mode) && lp_fake_dir_create_times()) {
+       if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
                dst->st_ex_btime.tv_sec = 315493200L;          /* 1/1/1980 */
                dst->st_ex_btime.tv_nsec = 0;
        }
@@ -504,8 +505,22 @@ void update_stat_ex_mtime(struct stat_ex *dst,
        }
 }
 
+void update_stat_ex_create_time(struct stat_ex *dst,
+                                struct timespec create_time)
+{
+       dst->st_ex_btime = create_time;
+       dst->st_ex_calculated_birthtime = false;
+}
+
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
 static void init_stat_ex_from_stat (struct stat_ex *dst,
-                                   const struct stat *src)
+                                   const struct stat64 *src,
+                                   bool fake_dir_create_times)
+#else
+static void init_stat_ex_from_stat (struct stat_ex *dst,
+                                   const struct stat *src,
+                                   bool fake_dir_create_times)
+#endif
 {
        dst->st_ex_dev = src->st_dev;
        dst->st_ex_ino = src->st_ino;
@@ -518,7 +533,7 @@ static void init_stat_ex_from_stat (struct stat_ex *dst,
        dst->st_ex_atime = get_atimespec(src);
        dst->st_ex_mtime = get_mtimespec(src);
        dst->st_ex_ctime = get_ctimespec(src);
-       get_create_timespec(src, dst);
+       make_create_timespec(src, dst, fake_dir_create_times);
        dst->st_ex_blksize = src->st_blksize;
        dst->st_ex_blocks = src->st_blocks;
 
@@ -533,11 +548,13 @@ static void init_stat_ex_from_stat (struct stat_ex *dst,
 A stat() wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
 
-int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
+int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
+            bool fake_dir_create_times)
 {
        int ret;
 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
-       ret = stat64(fname, sbuf);
+       struct stat64 statbuf;
+       ret = stat64(fname, &statbuf);
 #else
        struct stat statbuf;
        ret = stat(fname, &statbuf);
@@ -547,7 +564,7 @@ int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
                if (S_ISDIR(statbuf.st_mode)) {
                        statbuf.st_size = 0;
                }
-               init_stat_ex_from_stat(sbuf, &statbuf);
+               init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
        }
        return ret;
 }
@@ -556,11 +573,12 @@ int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
  An fstat() wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
 
-int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
+int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
 {
        int ret;
 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
-       ret = fstat64(fd, sbuf);
+       struct stat64 statbuf;
+       ret = fstat64(fd, &statbuf);
 #else
        struct stat statbuf;
        ret = fstat(fd, &statbuf);
@@ -570,7 +588,7 @@ int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
                if (S_ISDIR(statbuf.st_mode)) {
                        statbuf.st_size = 0;
                }
-               init_stat_ex_from_stat(sbuf, &statbuf);
+               init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
        }
        return ret;
 }
@@ -579,11 +597,13 @@ int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
  An lstat() wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
 
-int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
+int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
+             bool fake_dir_create_times)
 {
        int ret;
 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
-       ret = lstat64(fname, sbuf);
+       struct stat64 statbuf;
+       ret = lstat64(fname, &statbuf);
 #else
        struct stat statbuf;
        ret = lstat(fname, &statbuf);
@@ -593,11 +613,25 @@ int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
                if (S_ISDIR(statbuf.st_mode)) {
                        statbuf.st_size = 0;
                }
-               init_stat_ex_from_stat(sbuf, &statbuf);
+               init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
        }
        return ret;
 }
 
+/*******************************************************************
+ An posix_fallocate() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_POSIX_FALLOCATE64) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
+       return posix_fallocate64(fd, offset, len);
+#elif defined(HAVE_POSIX_FALLOCATE) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
+       return posix_fallocate(fd, offset, len);
+#else
+       return ENOSYS;
+#endif
+}
+
 /*******************************************************************
  An ftruncate() wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
@@ -702,7 +736,7 @@ FILE *sys_fopen(const char *path, const char *type)
  A flock() wrapper that will perform the kernel flock.
 ********************************************************************/
 
-void kernel_flock(int fd, uint32 share_mode)
+void kernel_flock(int fd, uint32 share_mode, uint32 access_mask)
 {
 #if HAVE_KERNEL_SHARE_MODES
        int kernel_mode = 0;
@@ -849,6 +883,11 @@ char *sys_getwd(char *s)
 
 #if defined(HAVE_POSIX_CAPABILITIES)
 
+/* This define hasn't made it into the glibc capabilities header yet. */
+#ifndef SECURE_NO_SETUID_FIXUP
+#define SECURE_NO_SETUID_FIXUP          2
+#endif
+
 /**************************************************************************
  Try and abstract process capabilities (for systems that have them).
 ****************************************************************************/
@@ -879,6 +918,32 @@ static bool set_process_capability(enum smbd_capability capability,
        }
 #endif
 
+#if defined(HAVE_PRCTL) && defined(PR_SET_SECUREBITS) && defined(SECURE_NO_SETUID_FIXUP)
+        /* New way of setting capabilities as "sticky". */
+
+       /*
+        * Use PR_SET_SECUREBITS to prevent setresuid()
+        * atomically dropping effective capabilities on
+        * uid change. Only available in Linux kernels
+        * 2.6.26 and above.
+        *
+        * See here:
+        * http://www.kernel.org/doc/man-pages/online/pages/man7/capabilities.7.html
+        * for details.
+        *
+        * Specifically the CAP_KILL capability we need
+        * to allow Linux threads under different euids
+        * to send signals to each other.
+        */
+
+       if (prctl(PR_SET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP)) {
+               DEBUG(0,("set_process_capability: "
+                       "prctl PR_SET_SECUREBITS failed with error %s\n",
+                       strerror(errno) ));
+               return false;
+       }
+#endif
+
        cap = cap_get_proc();
        if (cap == NULL) {
                DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
@@ -905,6 +970,11 @@ static bool set_process_capability(enum smbd_capability capability,
                case LEASE_CAPABILITY:
 #ifdef CAP_LEASE
                        cap_vals[num_cap_vals++] = CAP_LEASE;
+#endif
+                       break;
+               case KILL_CAPABILITY:
+#ifdef CAP_KILL
+                       cap_vals[num_cap_vals++] = CAP_KILL;
 #endif
                        break;
        }
@@ -916,16 +986,37 @@ static bool set_process_capability(enum smbd_capability capability,
                return True;
        }
 
-       cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
-               enable ? CAP_SET : CAP_CLEAR);
+       /*
+        * Ensure the capability is effective. We assume that as a root
+        * process it's always permitted.
+        */
+
+       if (cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
+                       enable ? CAP_SET : CAP_CLEAR) == -1) {
+               DEBUG(0, ("set_process_capability: cap_set_flag effective "
+                       "failed (%d): %s\n",
+                       (int)capability,
+                       strerror(errno)));
+               cap_free(cap);
+               return false;
+       }
 
        /* We never want to pass capabilities down to our children, so make
         * sure they are not inherited.
         */
-       cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
+       if (cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals,
+                       cap_vals, CAP_CLEAR) == -1) {
+               DEBUG(0, ("set_process_capability: cap_set_flag inheritable "
+                       "failed (%d): %s\n",
+                       (int)capability,
+                       strerror(errno)));
+               cap_free(cap);
+               return false;
+       }
 
        if (cap_set_proc(cap) == -1) {
-               DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
+               DEBUG(0, ("set_process_capability: cap_set_flag (%d) failed: %s\n",
+                       (int)capability,
                        strerror(errno)));
                cap_free(cap);
                return False;
@@ -1289,6 +1380,7 @@ static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
        }
 
        argl[i++] = NULL;
+       TALLOC_FREE(trunc_cmd);
        return argl;
 
  nomem: