r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[samba.git] / source3 / lib / system.c
index 6c36544b77509c6c85bdf6895cdc51b2c1d2fcb9..24c726b8f75ec6155822c9b430cbd7762437d2d0 100644 (file)
 
 #include "includes.h"
 
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
 /*
    The idea is that this file will eventually have wrappers around all
    important system calls in samba. The aims are:
@@ -366,7 +370,7 @@ FILE *sys_fopen(const char *path, const char *type)
  An opendir wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
 
-DIR *sys_opendir(const char *name)
+SMB_STRUCT_DIR *sys_opendir(const char *name)
 {
 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
        return opendir64(name);
@@ -379,7 +383,7 @@ DIR *sys_opendir(const char *name)
  A readdir wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
 
-SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
+SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
 {
 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
        return readdir64(dirp);
@@ -392,7 +396,7 @@ SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
  A seekdir wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
 
-void sys_seekdir(DIR *dirp, long offset)
+void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
 {
 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
        seekdir64(dirp, offset);
@@ -405,7 +409,7 @@ void sys_seekdir(DIR *dirp, long offset)
  A telldir wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
 
-long sys_telldir(DIR *dirp)
+long sys_telldir(SMB_STRUCT_DIR *dirp)
 {
 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
        return (long)telldir64(dirp);
@@ -418,7 +422,7 @@ long sys_telldir(DIR *dirp)
  A rewinddir wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
 
-void sys_rewinddir(DIR *dirp)
+void sys_rewinddir(SMB_STRUCT_DIR *dirp)
 {
 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
        rewinddir64(dirp);
@@ -431,7 +435,7 @@ void sys_rewinddir(DIR *dirp)
  A close wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
 
-int sys_closedir(DIR *dirp)
+int sys_closedir(SMB_STRUCT_DIR *dirp)
 {
 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
        return closedir64(dirp);
@@ -624,85 +628,125 @@ struct hostent *sys_gethostbyname(const char *name)
 }
 
 
-#if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
-/**************************************************************************
- Try and abstract process capabilities (for systems that have them).
-****************************************************************************/
-static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
-{
-       if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
-               cap_t cap = cap_get_proc();
+#if defined(HAVE_POSIX_CAPABILITIES)
 
-               if (cap == NULL) {
-                       DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
-                               strerror(errno)));
-                       return False;
-               }
+#ifdef HAVE_SYS_CAPABILITY_H
 
-               if(enable)
-                       cap->cap_effective |= CAP_NETWORK_MGT;
-               else
-                       cap->cap_effective &= ~CAP_NETWORK_MGT;
+#if defined(BROKEN_REDHAT_7_SYSTEM_HEADERS) && !defined(_I386_STATFS_H) && !defined(_PPC_STATFS_H)
+#define _I386_STATFS_H
+#define _PPC_STATFS_H
+#define BROKEN_REDHAT_7_STATFS_WORKAROUND
+#endif
 
-               if (cap_set_proc(cap) == -1) {
-                       DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
-                               strerror(errno)));
-                       cap_free(cap);
-                       return False;
-               }
+#include <sys/capability.h>
 
-               cap_free(cap);
+#ifdef BROKEN_REDHAT_7_STATFS_WORKAROUND
+#undef _I386_STATFS_H
+#undef _PPC_STATFS_H
+#undef BROKEN_REDHAT_7_STATFS_WORKAROUND
+#endif
 
-               DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
-       }
-       return True;
-}
+#endif /* HAVE_SYS_CAPABILITY_H */
 
 /**************************************************************************
- Try and abstract inherited process capabilities (for systems that have them).
+ Try and abstract process capabilities (for systems that have them).
 ****************************************************************************/
 
-static BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
-{
-       if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
-               cap_t cap = cap_get_proc();
+/* Set the POSIX capabilities needed for the given purpose into the effective
+ * capability set of the current process. Make sure they are always removed
+ * from the inheritable set, because there is no circumstance in which our
+ * children should inherit our elevated privileges.
+ */
+static BOOL set_process_capability(enum smbd_capability capability,
+                                  BOOL enable)
+{
+       cap_value_t cap_vals[2] = {0};
+       int num_cap_vals = 0;
+
+       cap_t cap;
+
+#if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
+       /* On Linux, make sure that any capabilities we grab are sticky
+        * across UID changes. We expect that this would allow us to keep both
+        * the effective and permitted capability sets, but as of circa 2.6.16,
+        * only the permitted set is kept. It is a bug (which we work around)
+        * that the effective set is lost, but we still require the effective
+        * set to be kept.
+        */
+       if (!prctl(PR_GET_KEEPCAPS)) {
+               prctl(PR_SET_KEEPCAPS, 1);
+       }
+#endif
 
-               if (cap == NULL) {
-                       DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
-                               strerror(errno)));
-                       return False;
-               }
+       cap = cap_get_proc();
+       if (cap == NULL) {
+               DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
+                       strerror(errno)));
+               return False;
+       }
 
-               if(enable)
-                       cap->cap_inheritable |= CAP_NETWORK_MGT;
-               else
-                       cap->cap_inheritable &= ~CAP_NETWORK_MGT;
+       switch (capability) {
+               case KERNEL_OPLOCK_CAPABILITY:
+#ifdef CAP_NETWORK_MGT
+                       /* IRIX has CAP_NETWORK_MGT for oplocks. */
+                       cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
+#endif
+                       break;
+               case DMAPI_ACCESS_CAPABILITY:
+#ifdef CAP_DEVICE_MGT
+                       /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
+                       cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
+#elif CAP_MKNOD
+                       /* Linux has CAP_MKNOD for DMAPI access. */
+                       cap_vals[num_cap_vals++] = CAP_MKNOD;
+#endif
+                       break;
+       }
 
-               if (cap_set_proc(cap) == -1) {
-                       DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
-                               strerror(errno)));
-                       cap_free(cap);
-                       return False;
-               }
+       SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
 
+       if (num_cap_vals == 0) {
                cap_free(cap);
+               return True;
+       }
 
-               DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
+       cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
+               enable ? CAP_SET : CAP_CLEAR);
+
+       /* 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_proc(cap) == -1) {
+               DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
+                       strerror(errno)));
+               cap_free(cap);
+               return False;
        }
+
+       cap_free(cap);
        return True;
 }
-#endif
+
+#endif /* HAVE_POSIX_CAPABILITIES */
 
 /****************************************************************************
  Gain the oplock capability from the kernel if possible.
 ****************************************************************************/
 
-void oplock_set_capability(BOOL this_process, BOOL inherit)
+void set_effective_capability(enum smbd_capability capability)
 {
-#if HAVE_KERNEL_OPLOCKS_IRIX
-       set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
-       set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
-#endif
+#if defined(HAVE_POSIX_CAPABILITIES)
+       set_process_capability(capability, True);
+#endif /* HAVE_POSIX_CAPABILITIES */
+}
+
+void drop_effective_capability(enum smbd_capability capability)
+{
+#if defined(HAVE_POSIX_CAPABILITIES)
+       set_process_capability(capability, False);
+#endif /* HAVE_POSIX_CAPABILITIES */
 }
 
 /**************************************************************************
@@ -878,16 +922,94 @@ void sys_endpwent(void)
  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
 ****************************************************************************/
 
+#ifdef ENABLE_BUILD_FARM_HACKS
+
+/*
+ * In the build farm we want to be able to join machines to the domain. As we
+ * don't have root access, we need to bypass direct access to /etc/passwd
+ * after a user has been created via samr. Fake those users.
+ */
+
+static struct passwd *fake_pwd;
+static int num_fake_pwd;
+
 struct passwd *sys_getpwnam(const char *name)
 {
+       int i;
+
+       for (i=0; i<num_fake_pwd; i++) {
+               if (strcmp(fake_pwd[i].pw_name, name) == 0) {
+                       DEBUG(10, ("Returning fake user %s\n", name));
+                       return &fake_pwd[i];
+               }
+       }
+
        return getpwnam(name);
 }
 
 struct passwd *sys_getpwuid(uid_t uid)
 {
+       int i;
+
+       for (i=0; i<num_fake_pwd; i++) {
+               if (fake_pwd[i].pw_uid == uid) {
+                       DEBUG(10, ("Returning fake user %s\n",
+                                  fake_pwd[i].pw_name));
+                       return &fake_pwd[i];
+               }
+       }
+
        return getpwuid(uid);
 }
 
+void faked_create_user(const char *name)
+{
+       int i;
+       uid_t uid;
+       struct passwd new_pwd;
+
+       for (i=0; i<10; i++) {
+               generate_random_buffer((unsigned char *)&uid,
+                                      sizeof(uid));
+               if (getpwuid(uid) == NULL) {
+                       break;
+               }
+       }
+
+       if (i==10) {
+               /* Weird. No free uid found... */
+               return;
+       }
+
+       new_pwd.pw_name = SMB_STRDUP(name);
+       new_pwd.pw_passwd = SMB_STRDUP("x");
+       new_pwd.pw_uid = uid;
+       new_pwd.pw_gid = 100;
+       new_pwd.pw_gecos = SMB_STRDUP("faked user");
+       new_pwd.pw_dir = SMB_STRDUP("/nodir");
+       new_pwd.pw_shell = SMB_STRDUP("/bin/false");
+
+       ADD_TO_ARRAY(NULL, struct passwd, new_pwd, &fake_pwd,
+                    &num_fake_pwd);
+
+       DEBUG(10, ("Added fake user %s, have %d fake users\n",
+                  name, num_fake_pwd));
+}
+
+#else
+
+struct passwd *sys_getpwnam(const char *name)
+{
+       return getpwnam(name);
+}
+
+struct passwd *sys_getpwuid(uid_t uid)
+{
+       return getpwuid(uid);
+}
+
+#endif
+
 struct group *sys_getgrnam(const char *name)
 {
        return getgrnam(name);
@@ -960,7 +1082,7 @@ FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
  Wide opendir. Just narrow and call sys_xxx.
 ****************************************************************************/
 
-DIR *wsys_opendir(const smb_ucs2_t *wfname)
+SMB_STRUCT_DIR *wsys_opendir(const smb_ucs2_t *wfname)
 {
        pstring fname;
        return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
@@ -970,7 +1092,7 @@ DIR *wsys_opendir(const smb_ucs2_t *wfname)
  Wide readdir. Return a structure pointer containing a wide filename.
 ****************************************************************************/
 
-SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
+SMB_STRUCT_WDIRENT *wsys_readdir(SMB_STRUCT_DIR *dirp)
 {
        static SMB_STRUCT_WDIRENT retval;
        SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
@@ -1367,20 +1489,37 @@ int sys_dup2(int oldfd, int newfd)
 
 /**************************************************************************
  Wrappers for extented attribute calls. Based on the Linux package with
- support for IRIX also. Expand as other systems have them.
+ support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
 ****************************************************************************/
 
 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
 {
 #if defined(HAVE_GETXATTR)
        return getxattr(path, name, value, size);
+#elif defined(HAVE_GETEA)
+       return getea(path, name, value, size);
 #elif defined(HAVE_EXTATTR_GET_FILE)
        char *s;
+       ssize_t retval;
        int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
                EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
        const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+       /*
+        * The BSD implementation has a nasty habit of silently truncating
+        * the returned value to the size of the buffer, so we have to check
+        * that the buffer is large enough to fit the returned value.
+        */
+       if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
+               if(retval > size) {
+                       errno = ERANGE;
+                       return -1;
+               }
+               if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
+                       return retval;
+       }
 
-       return extattr_get_file(path, attrnamespace, attrname, value, size);
+       DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
+       return -1;
 #elif defined(HAVE_ATTR_GET)
        int retval, flags = 0;
        int valuelength = (int)size;
@@ -1401,13 +1540,26 @@ ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t s
 {
 #if defined(HAVE_LGETXATTR)
        return lgetxattr(path, name, value, size);
+#elif defined(HAVE_LGETEA)
+       return lgetea(path, name, value, size);
 #elif defined(HAVE_EXTATTR_GET_LINK)
        char *s;
+       ssize_t retval;
        int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
                EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
        const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
 
-       return extattr_get_link(path, attrnamespace, attrname, value, size);
+       if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
+               if(retval > size) {
+                       errno = ERANGE;
+                       return -1;
+               }
+               if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
+                       return retval;
+       }
+       
+       DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
+       return -1;
 #elif defined(HAVE_ATTR_GET)
        int retval, flags = ATTR_DONTFOLLOW;
        int valuelength = (int)size;
@@ -1428,13 +1580,26 @@ ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
 {
 #if defined(HAVE_FGETXATTR)
        return fgetxattr(filedes, name, value, size);
+#elif defined(HAVE_FGETEA)
+       return fgetea(filedes, name, value, size);
 #elif defined(HAVE_EXTATTR_GET_FD)
        char *s;
+       ssize_t retval;
        int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
                EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
        const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
 
-       return extattr_get_fd(filedes, attrnamespace, attrname, value, size);
+       if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
+               if(retval > size) {
+                       errno = ERANGE;
+                       return -1;
+               }
+               if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
+                       return retval;
+       }
+       
+       DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
+       return -1;
 #elif defined(HAVE_ATTR_GETF)
        int retval, flags = 0;
        int valuelength = (int)size;
@@ -1526,7 +1691,7 @@ static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size
                        errno = ERANGE;
                        return -1;
                }
-               /* Shift the results back, so we can prepend prefixes */
+               /* Shift results back, so we can prepend prefixes */
                buf = memmove(list + len, list, list_size);
 
                for(i = 0; i < list_size; i += len + 1) {
@@ -1616,6 +1781,8 @@ ssize_t sys_listxattr (const char *path, char *list, size_t size)
 {
 #if defined(HAVE_LISTXATTR)
        return listxattr(path, list, size);
+#elif defined(HAVE_LISTEA)
+       return listea(path, list, size);
 #elif defined(HAVE_EXTATTR_LIST_FILE)
        extattr_arg arg;
        arg.path = path;
@@ -1632,6 +1799,8 @@ ssize_t sys_llistxattr (const char *path, char *list, size_t size)
 {
 #if defined(HAVE_LLISTXATTR)
        return llistxattr(path, list, size);
+#elif defined(HAVE_LLISTEA)
+       return llistea(path, list, size);
 #elif defined(HAVE_EXTATTR_LIST_LINK)
        extattr_arg arg;
        arg.path = path;
@@ -1648,6 +1817,8 @@ ssize_t sys_flistxattr (int filedes, char *list, size_t size)
 {
 #if defined(HAVE_FLISTXATTR)
        return flistxattr(filedes, list, size);
+#elif defined(HAVE_FLISTEA)
+       return flistea(filedes, list, size);
 #elif defined(HAVE_EXTATTR_LIST_FD)
        extattr_arg arg;
        arg.filedes = filedes;
@@ -1664,6 +1835,8 @@ int sys_removexattr (const char *path, const char *name)
 {
 #if defined(HAVE_REMOVEXATTR)
        return removexattr(path, name);
+#elif defined(HAVE_REMOVEEA)
+       return removeea(path, name);
 #elif defined(HAVE_EXTATTR_DELETE_FILE)
        char *s;
        int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
@@ -1688,6 +1861,8 @@ int sys_lremovexattr (const char *path, const char *name)
 {
 #if defined(HAVE_LREMOVEXATTR)
        return lremovexattr(path, name);
+#elif defined(HAVE_LREMOVEEA)
+       return lremoveea(path, name);
 #elif defined(HAVE_EXTATTR_DELETE_LINK)
        char *s;
        int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
@@ -1712,6 +1887,8 @@ int sys_fremovexattr (int filedes, const char *name)
 {
 #if defined(HAVE_FREMOVEXATTR)
        return fremovexattr(filedes, name);
+#elif defined(HAVE_FREMOVEEA)
+       return fremoveea(filedes, name);
 #elif defined(HAVE_EXTATTR_DELETE_FD)
        char *s;
        int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
@@ -1741,13 +1918,33 @@ int sys_setxattr (const char *path, const char *name, const void *value, size_t
 {
 #if defined(HAVE_SETXATTR)
        return setxattr(path, name, value, size, flags);
+#elif defined(HAVE_SETEA)
+       return setea(path, name, value, size, flags);
 #elif defined(HAVE_EXTATTR_SET_FILE)
        char *s;
        int retval = 0;
        int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
                EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
        const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
-
+       if (flags) {
+               /* Check attribute existence */
+               retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
+               if (retval < 0) {
+                       /* REPLACE attribute, that doesn't exist */
+                       if (flags & XATTR_REPLACE && errno == ENOATTR) {
+                               errno = ENOATTR;
+                               return -1;
+                       }
+                       /* Ignore other errors */
+               }
+               else {
+                       /* CREATE attribute, that already exists */
+                       if (flags & XATTR_CREATE) {
+                               errno = EEXIST;
+                               return -1;
+                       }
+               }
+       }
        retval = extattr_set_file(path, attrnamespace, attrname, value, size);
        return (retval < 0) ? -1 : 0;
 #elif defined(HAVE_ATTR_SET)
@@ -1769,12 +1966,33 @@ int sys_lsetxattr (const char *path, const char *name, const void *value, size_t
 {
 #if defined(HAVE_LSETXATTR)
        return lsetxattr(path, name, value, size, flags);
+#elif defined(LSETEA)
+       return lsetea(path, name, value, size, flags);
 #elif defined(HAVE_EXTATTR_SET_LINK)
        char *s;
        int retval = 0;
        int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
                EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
        const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+       if (flags) {
+               /* Check attribute existence */
+               retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
+               if (retval < 0) {
+                       /* REPLACE attribute, that doesn't exist */
+                       if (flags & XATTR_REPLACE && errno == ENOATTR) {
+                               errno = ENOATTR;
+                               return -1;
+                       }
+                       /* Ignore other errors */
+               }
+               else {
+                       /* CREATE attribute, that already exists */
+                       if (flags & XATTR_CREATE) {
+                               errno = EEXIST;
+                               return -1;
+                       }
+               }
+       }
 
        retval = extattr_set_link(path, attrnamespace, attrname, value, size);
        return (retval < 0) ? -1 : 0;
@@ -1797,13 +2015,33 @@ int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size
 {
 #if defined(HAVE_FSETXATTR)
        return fsetxattr(filedes, name, value, size, flags);
+#elif defined(HAVE_FSETEA)
+       return fsetea(filedes, name, value, size, flags);
 #elif defined(HAVE_EXTATTR_SET_FD)
        char *s;
        int retval = 0;
        int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
                EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
        const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
-
+       if (flags) {
+               /* Check attribute existence */
+               retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
+               if (retval < 0) {
+                       /* REPLACE attribute, that doesn't exist */
+                       if (flags & XATTR_REPLACE && errno == ENOATTR) {
+                               errno = ENOATTR;
+                               return -1;
+                       }
+                       /* Ignore other errors */
+               }
+               else {
+                       /* CREATE attribute, that already exists */
+                       if (flags & XATTR_CREATE) {
+                               errno = EEXIST;
+                               return -1;
+                       }
+               }
+       }
        retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
        return (retval < 0) ? -1 : 0;
 #elif defined(HAVE_ATTR_SETF)
@@ -1846,3 +2084,161 @@ uint32 unix_dev_minor(SMB_DEV_T dev)
         return (uint32)(dev & 0xff);
 #endif
 }
+
+#if defined(WITH_AIO)
+
+/*******************************************************************
+ An aio_read wrapper that will deal with 64-bit sizes.
+********************************************************************/
+                                                                                                                                           
+int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
+        return aio_read64(aiocb);
+#elif defined(HAVE_AIO_READ)
+        return aio_read(aiocb);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_write wrapper that will deal with 64-bit sizes.
+********************************************************************/
+                                                                                                                                           
+int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
+        return aio_write64(aiocb);
+#elif defined(HAVE_AIO_WRITE)
+        return aio_write(aiocb);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_return wrapper that will deal with 64-bit sizes.
+********************************************************************/
+                                                                                                                                           
+ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
+        return aio_return64(aiocb);
+#elif defined(HAVE_AIO_RETURN)
+        return aio_return(aiocb);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_cancel wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
+        return aio_cancel64(fd, aiocb);
+#elif defined(HAVE_AIO_CANCEL)
+        return aio_cancel(fd, aiocb);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_error wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
+        return aio_error64(aiocb);
+#elif defined(HAVE_AIO_ERROR)
+        return aio_error(aiocb);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_fsync wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
+        return aio_fsync64(op, aiocb);
+#elif defined(HAVE_AIO_FSYNC)
+        return aio_fsync(op, aiocb);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_fsync wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
+        return aio_suspend64(cblist, n, timeout);
+#elif defined(HAVE_AIO_FSYNC)
+        return aio_suspend(cblist, n, timeout);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+#else /* !WITH_AIO */
+
+int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
+{
+       errno = ENOSYS;
+       return -1;
+}
+#endif /* WITH_AIO */