r23470: Fix supplementary group list truncation for *BSD. We need to pass
[sfrench/samba-autobuild/.git] / source / lib / system.c
index 2e5f42307bdf3e09114ef12999ef3e729935d673..13f743faa4f9e36505f607bfec33fa1f38a7a496 100644 (file)
 
 
 
+/*******************************************************************
+ A wrapper for memalign
+********************************************************************/
+
+void *sys_memalign( size_t align, size_t size )
+{
+#if defined(HAVE_POSIX_MEMALIGN)
+       void *p = NULL;
+       int ret = posix_memalign( &p, align, size );
+       if ( ret == 0 )
+               return p;
+               
+       return NULL;
+#elif defined(HAVE_MEMALIGN)
+       return memalign( align, size );
+#else
+       /* On *BSD systems memaligns doesn't exist, but memory will
+        * be aligned on allocations of > pagesize. */
+#if defined(SYSCONF_SC_PAGESIZE)
+       size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
+#elif defined(HAVE_GETPAGESIZE)
+       size_t pagesize = (size_t)getpagesize();
+#else
+       size_t pagesize = (size_t)-1;
+#endif
+       if (pagesize == (size_t)-1) {
+               DEBUG(0,("memalign functionalaity not available on this platform!\n"));
+               return NULL;
+       }
+       if (size < pagesize) {
+               size = pagesize;
+       }
+       return SMB_MALLOC(size);
+#endif
+}
+
 /*******************************************************************
  A wrapper for usleep in case we don't have one.
 ********************************************************************/
@@ -105,7 +141,6 @@ ssize_t sys_write(int fd, const void *buf, size_t count)
        return ret;
 }
 
-
 /*******************************************************************
 A pread wrapper that will deal with EINTR and 64-bit file offsets.
 ********************************************************************/
@@ -174,6 +209,20 @@ ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct
        return ret;
 }
 
+/*******************************************************************
+A recv wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_recv(int fd, void *buf, size_t count, int flags)
+{
+       ssize_t ret;
+
+       do {
+               ret = recv(fd, buf, count, flags);
+       } while (ret == -1 && errno == EINTR);
+       return ret;
+}
+
 /*******************************************************************
 A recvfrom wrapper that will deal with EINTR.
 ********************************************************************/
@@ -366,6 +415,31 @@ FILE *sys_fopen(const char *path, const char *type)
 #endif
 }
 
+
+/*******************************************************************
+ A flock() wrapper that will perform the kernel flock.
+********************************************************************/
+
+void kernel_flock(int fd, uint32 share_mode)
+{
+#if HAVE_KERNEL_SHARE_MODES
+       int kernel_mode = 0;
+       if (share_mode == FILE_SHARE_WRITE) {
+               kernel_mode = LOCK_MAND|LOCK_WRITE;
+       } else if (share_mode == FILE_SHARE_READ) {
+               kernel_mode = LOCK_MAND|LOCK_READ;
+       } else if (share_mode == FILE_SHARE_NONE) {
+               kernel_mode = LOCK_MAND;
+       }
+       if (kernel_mode) {
+               flock(fd, kernel_mode);
+       }
+#endif
+       ;
+}
+
+
+
 /*******************************************************************
  An opendir wrapper that will deal with 64 bit filesizes.
 ********************************************************************/
@@ -567,6 +641,25 @@ int sys_chown(const char *fname,uid_t uid,gid_t gid)
 #endif
 }
 
+/*******************************************************************
+ Wrapper for lchown.
+********************************************************************/
+
+int sys_lchown(const char *fname,uid_t uid,gid_t gid)
+{
+#ifndef HAVE_LCHOWN
+       static int done;
+       if (!done) {
+               DEBUG(1,("WARNING: no lchown!\n"));
+               done=1;
+       }
+       errno = ENOSYS;
+       return -1;
+#else
+       return(lchown(fname,uid,gid));
+#endif
+}
+
 /*******************************************************************
 os/2 also doesn't have chroot
 ********************************************************************/
@@ -796,15 +889,13 @@ int groups_max(void)
 }
 
 /**************************************************************************
- Wrapper for getgroups. Deals with broken (int) case.
+ Wrap setgroups and getgroups for systems that declare getgroups() as
+ returning an array of gid_t, but actuall return an array of int.
 ****************************************************************************/
 
-int sys_getgroups(int setlen, gid_t *gidset)
+#if defined(HAVE_BROKEN_GETGROUPS)
+static int sys_broken_getgroups(int setlen, gid_t *gidset)
 {
-#if !defined(HAVE_BROKEN_GETGROUPS)
-       return getgroups(setlen, gidset);
-#else
-
        GID_T gid;
        GID_T *group_list;
        int i, ngroups;
@@ -826,7 +917,7 @@ int sys_getgroups(int setlen, gid_t *gidset)
        if (setlen == 0)
                setlen = groups_max();
 
-       if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
+       if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
                DEBUG(0,("sys_getgroups: Malloc fail.\n"));
                return -1;
        }
@@ -843,26 +934,10 @@ int sys_getgroups(int setlen, gid_t *gidset)
 
        SAFE_FREE(group_list);
        return ngroups;
-#endif /* HAVE_BROKEN_GETGROUPS */
 }
 
-
-/**************************************************************************
- Wrapper for setgroups. Deals with broken (int) case. Automatically used
- if we have broken getgroups.
-****************************************************************************/
-
-int sys_setgroups(int setlen, gid_t *gidset)
+static int sys_broken_setgroups(gid_t primary_gid, int setlen, gid_t *gidset)
 {
-#if !defined(HAVE_SETGROUPS)
-       errno = ENOSYS;
-       return -1;
-#endif /* HAVE_SETGROUPS */
-
-#if !defined(HAVE_BROKEN_GETGROUPS)
-       return setgroups(setlen, gidset);
-#else
-
        GID_T *group_list;
        int i ; 
 
@@ -879,7 +954,7 @@ int sys_setgroups(int setlen, gid_t *gidset)
         * GID_T array of size setlen.
         */
 
-       if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
+       if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
                DEBUG(0,("sys_setgroups: Malloc fail.\n"));
                return -1;    
        }
@@ -896,7 +971,107 @@ int sys_setgroups(int setlen, gid_t *gidset)
  
        SAFE_FREE(group_list);
        return 0 ;
+}
+
 #endif /* HAVE_BROKEN_GETGROUPS */
+
+/* This is a list of systems that require the first GID passed to setgroups(2)
+ * to be the effective GID. If your system is one of these, add it here.
+ */
+#if defined (FREEBSD) || defined (DARWINOS)
+#define USE_BSD_SETGROUPS
+#endif
+
+#if defined(USE_BSD_SETGROUPS)
+/* Depending on the particular BSD implementation, the first GID that is
+ * passed to setgroups(2) will either be ignored or will set the credential's
+ * effective GID. In either case, the right thing to do is to guarantee that
+ * gidset[0] is the effective GID.
+ */
+static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
+{
+       gid_t *new_gidset = NULL;
+       int max;
+       int ret;
+
+       /* setgroups(2) will fail with EINVAL if we pass too many groups. */
+       max = groups_max();
+
+       /* No group list, just make sure we are setting the efective GID. */
+       if (setlen == 0) {
+               return setgroups(1, &primary_gid);
+       }
+
+       /* If the primary gid is not the first array element, grow the array
+        * and insert it at the front.
+        */
+       if (gidset[0] != primary_gid) {
+               gid_t *new_gidset;
+
+               new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
+               if (new_gidset == NULL) {
+                       return -1;
+               }
+
+               memcpy(new_gidset + 1, gidset, ((setlen + 1) * sizeof(gid_t)));
+               new_gidset[0] = primary_gid;
+               setlen++;
+       }
+
+       if (setlen > max) {
+               DEBUG(10, ("forced to truncate group list from %d to %d\n",
+                       setlen, max));
+               setlen = max;
+       }
+
+#if defined(BROKEN_GETGROUPS)
+       ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
+#else
+       ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
+#endif
+
+       if (new_gidset) {
+               int errsav = errno;
+               SAFE_FREE(new_gidset);
+               errno = errsav;
+       }
+
+       return ret;
+}
+
+#endif /* USE_BSD_SETGROUPS */
+
+/**************************************************************************
+ Wrapper for getgroups. Deals with broken (int) case.
+****************************************************************************/
+
+int sys_getgroups(int setlen, gid_t *gidset)
+{
+#if defined(HAVE_BROKEN_GETGROUPS)
+       return sys_broken_getgroups(setlen, gidset);
+#else
+       return getgroups(setlen, gidset);
+#endif
+}
+
+/**************************************************************************
+ Wrapper for setgroups. Deals with broken (int) case and BSD case.
+****************************************************************************/
+
+int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
+{
+#if !defined(HAVE_SETGROUPS)
+       errno = ENOSYS;
+       return -1;
+#endif /* HAVE_SETGROUPS */
+
+#if defined(HAVE_BROKEN_GETGROUPS)
+       return sys_broken_setgroups(setlen, gidset);
+#elif defined(USE_BSD_SETGROUPS)
+       return sys_bsd_setgroups(primary_gid, setlen, gidset);
+#else
+       return setgroups(setlen, gidset);
+#endif
 }
 
 /**************************************************************************
@@ -922,16 +1097,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);
@@ -1417,7 +1670,12 @@ int sys_dup2(int oldfd, int newfd)
 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
 {
 #if defined(HAVE_GETXATTR)
+#ifndef XATTR_ADD_OPT
        return getxattr(path, name, value, size);
+#else
+       int options = 0;
+       return getxattr(path, name, value, size, 0, options);
+#endif
 #elif defined(HAVE_GETEA)
        return getea(path, name, value, size);
 #elif defined(HAVE_EXTATTR_GET_FILE)
@@ -1462,6 +1720,9 @@ 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_GETXATTR) && defined(XATTR_ADD_OPT)
+       int options = XATTR_NOFOLLOW;
+       return getxattr(path, name, value, size, 0, options);
 #elif defined(HAVE_LGETEA)
        return lgetea(path, name, value, size);
 #elif defined(HAVE_EXTATTR_GET_LINK)
@@ -1501,7 +1762,12 @@ ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t s
 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
 {
 #if defined(HAVE_FGETXATTR)
+#ifndef XATTR_ADD_OPT
        return fgetxattr(filedes, name, value, size);
+#else
+       int options = 0;
+       return fgetxattr(filedes, name, value, size, 0, options);
+#endif
 #elif defined(HAVE_FGETEA)
        return fgetea(filedes, name, value, size);
 #elif defined(HAVE_EXTATTR_GET_FD)
@@ -1702,7 +1968,12 @@ static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t
 ssize_t sys_listxattr (const char *path, char *list, size_t size)
 {
 #if defined(HAVE_LISTXATTR)
+#ifndef XATTR_ADD_OPT
        return listxattr(path, list, size);
+#else
+       int options = 0;
+       return listxattr(path, list, size, options);
+#endif
 #elif defined(HAVE_LISTEA)
        return listea(path, list, size);
 #elif defined(HAVE_EXTATTR_LIST_FILE)
@@ -1721,6 +1992,9 @@ ssize_t sys_llistxattr (const char *path, char *list, size_t size)
 {
 #if defined(HAVE_LLISTXATTR)
        return llistxattr(path, list, size);
+#elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
+       int options = XATTR_NOFOLLOW;
+       return listxattr(path, list, size, options);
 #elif defined(HAVE_LLISTEA)
        return llistea(path, list, size);
 #elif defined(HAVE_EXTATTR_LIST_LINK)
@@ -1738,7 +2012,12 @@ ssize_t sys_llistxattr (const char *path, char *list, size_t size)
 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
 {
 #if defined(HAVE_FLISTXATTR)
+#ifndef XATTR_ADD_OPT
        return flistxattr(filedes, list, size);
+#else
+       int options = 0;
+       return flistxattr(filedes, list, size, options);
+#endif
 #elif defined(HAVE_FLISTEA)
        return flistea(filedes, list, size);
 #elif defined(HAVE_EXTATTR_LIST_FD)
@@ -1756,7 +2035,12 @@ ssize_t sys_flistxattr (int filedes, char *list, size_t size)
 int sys_removexattr (const char *path, const char *name)
 {
 #if defined(HAVE_REMOVEXATTR)
+#ifndef XATTR_ADD_OPT
        return removexattr(path, name);
+#else
+       int options = 0;
+       return removexattr(path, name, options);
+#endif
 #elif defined(HAVE_REMOVEEA)
        return removeea(path, name);
 #elif defined(HAVE_EXTATTR_DELETE_FILE)
@@ -1783,6 +2067,9 @@ int sys_lremovexattr (const char *path, const char *name)
 {
 #if defined(HAVE_LREMOVEXATTR)
        return lremovexattr(path, name);
+#elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
+       int options = XATTR_NOFOLLOW;
+       return removexattr(path, name, options);
 #elif defined(HAVE_LREMOVEEA)
        return lremoveea(path, name);
 #elif defined(HAVE_EXTATTR_DELETE_LINK)
@@ -1808,7 +2095,12 @@ int sys_lremovexattr (const char *path, const char *name)
 int sys_fremovexattr (int filedes, const char *name)
 {
 #if defined(HAVE_FREMOVEXATTR)
+#ifndef XATTR_ADD_OPT
        return fremovexattr(filedes, name);
+#else
+       int options = 0;
+       return fremovexattr(filedes, name, options);
+#endif
 #elif defined(HAVE_FREMOVEEA)
        return fremoveea(filedes, name);
 #elif defined(HAVE_EXTATTR_DELETE_FD)
@@ -1839,7 +2131,12 @@ int sys_fremovexattr (int filedes, const char *name)
 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
 {
 #if defined(HAVE_SETXATTR)
+#ifndef XATTR_ADD_OPT
        return setxattr(path, name, value, size, flags);
+#else
+       int options = 0;
+       return setxattr(path, name, value, size, 0, options);
+#endif
 #elif defined(HAVE_SETEA)
        return setea(path, name, value, size, flags);
 #elif defined(HAVE_EXTATTR_SET_FILE)
@@ -1888,6 +2185,9 @@ 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(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
+       int options = XATTR_NOFOLLOW;
+       return setxattr(path, name, value, size, 0, options);
 #elif defined(LSETEA)
        return lsetea(path, name, value, size, flags);
 #elif defined(HAVE_EXTATTR_SET_LINK)
@@ -1936,7 +2236,12 @@ int sys_lsetxattr (const char *path, const char *name, const void *value, size_t
 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
 {
 #if defined(HAVE_FSETXATTR)
+#ifndef XATTR_ADD_OPT
        return fsetxattr(filedes, name, value, size, flags);
+#else
+       int options = 0;
+       return fsetxattr(filedes, name, value, size, 0, options);
+#endif
 #elif defined(HAVE_FSETEA)
        return fsetea(filedes, name, value, size, flags);
 #elif defined(HAVE_EXTATTR_SET_FD)
@@ -2164,3 +2469,28 @@ int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct
        return -1;
 }
 #endif /* WITH_AIO */
+
+int sys_getpeereid( int s, uid_t *uid)
+{
+#if defined(HAVE_PEERCRED)
+       struct ucred cred;
+       socklen_t cred_len = sizeof(struct ucred);
+       int ret;
+
+       ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
+       if (ret != 0) {
+               return -1;
+       }
+
+       if (cred_len != sizeof(struct ucred)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       *uid = cred.uid;
+       return 0;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}