2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 1998-2005
6 Copyright (C) Timur Bakeyev 2005
7 Copyright (C) Bjoern Jacke 2006-2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/syslog.h"
25 #include "system/capability.h"
26 #include "system/passwd.h"
27 #include "system/filesys.h"
28 #include "../lib/util/setid.h"
30 #ifdef HAVE_SYS_SYSCTL_H
31 #include <sys/sysctl.h>
34 #ifdef HAVE_SYS_PRCTL_H
35 #include <sys/prctl.h>
39 The idea is that this file will eventually have wrappers around all
40 important system calls in samba. The aims are:
42 - to enable easier porting by putting OS dependent stuff in here
44 - to allow for hooks into other "pseudo-filesystems"
46 - to allow easier integration of things like the japanese extensions
48 - to support the philosophy of Samba to expose the features of
49 the OS within the SMB model. In general whatever file/printer/variable
50 expansions/etc make sense to the OS should be acceptable to Samba.
53 /*******************************************************************
54 A send wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK.
55 ********************************************************************/
57 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
62 ret = send(s, msg, len, flags);
63 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
68 /*******************************************************************
69 A recvfrom wrapper that will deal with EINTR.
70 NB. As used with non-blocking sockets, return on EAGAIN/EWOULDBLOCK
71 ********************************************************************/
73 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
78 ret = recvfrom(s, buf, len, flags, from, fromlen);
79 } while (ret == -1 && (errno == EINTR));
83 /*******************************************************************
84 A fcntl wrapper that will deal with EINTR.
85 ********************************************************************/
87 int sys_fcntl_ptr(int fd, int cmd, void *arg)
92 ret = fcntl(fd, cmd, arg);
93 } while (ret == -1 && errno == EINTR);
97 /*******************************************************************
98 A fcntl wrapper that will deal with EINTR.
99 ********************************************************************/
101 int sys_fcntl_long(int fd, int cmd, long arg)
106 ret = fcntl(fd, cmd, arg);
107 } while (ret == -1 && errno == EINTR);
111 /*******************************************************************
112 A fcntl wrapper that will deal with EINTR.
113 ********************************************************************/
115 int sys_fcntl_int(int fd, int cmd, int arg)
120 ret = fcntl(fd, cmd, arg);
121 } while (ret == -1 && errno == EINTR);
125 /****************************************************************************
126 Get/Set all the possible time fields from a stat struct as a timespec.
127 ****************************************************************************/
129 static struct timespec get_atimespec(const struct stat *pst)
131 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
134 /* Old system - no ns timestamp. */
135 ret.tv_sec = pst->st_atime;
139 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
141 ret.tv_sec = pst->st_atim.tv_sec;
142 ret.tv_nsec = pst->st_atim.tv_nsec;
144 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
146 ret.tv_sec = pst->st_atime;
147 ret.tv_nsec = pst->st_atimensec;
149 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
151 ret.tv_sec = pst->st_atime;
152 ret.tv_nsec = pst->st_atime_n;
154 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
156 ret.tv_sec = pst->st_atime;
157 ret.tv_nsec = pst->st_uatime * 1000;
159 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
160 return pst->st_atimespec;
162 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
167 static struct timespec get_mtimespec(const struct stat *pst)
169 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
172 /* Old system - no ns timestamp. */
173 ret.tv_sec = pst->st_mtime;
177 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
179 ret.tv_sec = pst->st_mtim.tv_sec;
180 ret.tv_nsec = pst->st_mtim.tv_nsec;
182 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
184 ret.tv_sec = pst->st_mtime;
185 ret.tv_nsec = pst->st_mtimensec;
187 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
189 ret.tv_sec = pst->st_mtime;
190 ret.tv_nsec = pst->st_mtime_n;
192 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
194 ret.tv_sec = pst->st_mtime;
195 ret.tv_nsec = pst->st_umtime * 1000;
197 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
198 return pst->st_mtimespec;
200 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
205 static struct timespec get_ctimespec(const struct stat *pst)
207 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
210 /* Old system - no ns timestamp. */
211 ret.tv_sec = pst->st_ctime;
215 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
217 ret.tv_sec = pst->st_ctim.tv_sec;
218 ret.tv_nsec = pst->st_ctim.tv_nsec;
220 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
222 ret.tv_sec = pst->st_ctime;
223 ret.tv_nsec = pst->st_ctimensec;
225 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
227 ret.tv_sec = pst->st_ctime;
228 ret.tv_nsec = pst->st_ctime_n;
230 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
232 ret.tv_sec = pst->st_ctime;
233 ret.tv_nsec = pst->st_uctime * 1000;
235 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
236 return pst->st_ctimespec;
238 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
243 /****************************************************************************
244 Return the best approximation to a 'create time' under UNIX from a stat
246 ****************************************************************************/
248 static struct timespec calc_create_time_stat(const struct stat *st)
250 struct timespec ret, ret1;
251 struct timespec c_time = get_ctimespec(st);
252 struct timespec m_time = get_mtimespec(st);
253 struct timespec a_time = get_atimespec(st);
255 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
256 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
258 if(!null_timespec(ret1)) {
263 * One of ctime, mtime or atime was zero (probably atime).
264 * Just return MIN(ctime, mtime).
269 /****************************************************************************
270 Return the best approximation to a 'create time' under UNIX from a stat_ex
272 ****************************************************************************/
274 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
276 struct timespec ret, ret1;
277 struct timespec c_time = st->st_ex_ctime;
278 struct timespec m_time = st->st_ex_mtime;
279 struct timespec a_time = st->st_ex_atime;
281 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
282 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
284 if(!null_timespec(ret1)) {
289 * One of ctime, mtime or atime was zero (probably atime).
290 * Just return MIN(ctime, mtime).
295 /****************************************************************************
296 Return the 'create time' from a stat struct if it exists (birthtime) or else
297 use the best approximation.
298 ****************************************************************************/
300 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
301 bool fake_dir_create_times)
303 if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
304 dst->st_ex_btime.tv_sec = 315493200L; /* 1/1/1980 */
305 dst->st_ex_btime.tv_nsec = 0;
308 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
310 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
311 dst->st_ex_btime = pst->st_birthtimespec;
312 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
313 dst->st_ex_btime.tv_sec = pst->st_birthtime;
314 dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
315 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
316 dst->st_ex_btime.tv_sec = pst->st_birthtime;
317 dst->st_ex_btime.tv_nsec = 0;
319 dst->st_ex_btime = calc_create_time_stat(pst);
320 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
323 /* Deal with systems that don't initialize birthtime correctly.
324 * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
326 if (null_timespec(dst->st_ex_btime)) {
327 dst->st_ex_btime = calc_create_time_stat(pst);
328 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
331 dst->st_ex_itime = dst->st_ex_btime;
332 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_ITIME;
335 /****************************************************************************
336 If we update a timestamp in a stat_ex struct we may have to recalculate
337 the birthtime. For now only implement this for write time, but we may
338 also need to do it for atime and ctime. JRA.
339 ****************************************************************************/
341 void update_stat_ex_mtime(struct stat_ex *dst,
342 struct timespec write_ts)
344 dst->st_ex_mtime = write_ts;
346 /* We may have to recalculate btime. */
347 if (dst->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME) {
348 dst->st_ex_btime = calc_create_time_stat_ex(dst);
352 void update_stat_ex_create_time(struct stat_ex *dst,
353 struct timespec create_time)
355 dst->st_ex_btime = create_time;
356 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
359 void update_stat_ex_itime(struct stat_ex *dst,
360 struct timespec itime)
362 dst->st_ex_itime = itime;
363 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME;
366 void update_stat_ex_file_id(struct stat_ex *dst, uint64_t file_id)
368 dst->st_ex_file_id = file_id;
369 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_FILE_ID;
372 void update_stat_ex_from_saved_stat(struct stat_ex *dst,
373 const struct stat_ex *src)
375 if (!VALID_STAT(*src)) {
379 if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME)) {
380 update_stat_ex_create_time(dst, src->st_ex_btime);
383 if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
384 update_stat_ex_itime(dst, src->st_ex_itime);
387 if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
388 update_stat_ex_file_id(dst, src->st_ex_file_id);
392 void init_stat_ex_from_stat (struct stat_ex *dst,
393 const struct stat *src,
394 bool fake_dir_create_times)
396 dst->st_ex_dev = src->st_dev;
397 dst->st_ex_ino = src->st_ino;
398 dst->st_ex_mode = src->st_mode;
399 dst->st_ex_nlink = src->st_nlink;
400 dst->st_ex_uid = src->st_uid;
401 dst->st_ex_gid = src->st_gid;
402 dst->st_ex_rdev = src->st_rdev;
403 dst->st_ex_size = src->st_size;
404 dst->st_ex_atime = get_atimespec(src);
405 dst->st_ex_mtime = get_mtimespec(src);
406 dst->st_ex_ctime = get_ctimespec(src);
407 dst->st_ex_iflags = 0;
408 make_create_timespec(src, dst, fake_dir_create_times);
409 #ifdef HAVE_STAT_ST_BLKSIZE
410 dst->st_ex_blksize = src->st_blksize;
412 dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
415 #ifdef HAVE_STAT_ST_BLOCKS
416 dst->st_ex_blocks = src->st_blocks;
418 dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
421 #ifdef HAVE_STAT_ST_FLAGS
422 dst->st_ex_flags = src->st_flags;
424 dst->st_ex_flags = 0;
426 dst->st_ex_file_id = dst->st_ex_ino;
427 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_FILE_ID;
430 /*******************************************************************
432 ********************************************************************/
434 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
435 bool fake_dir_create_times)
439 ret = stat(fname, &statbuf);
441 /* we always want directories to appear zero size */
442 if (S_ISDIR(statbuf.st_mode)) {
445 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
450 /*******************************************************************
452 ********************************************************************/
454 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
458 ret = fstat(fd, &statbuf);
460 /* we always want directories to appear zero size */
461 if (S_ISDIR(statbuf.st_mode)) {
464 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
469 /*******************************************************************
471 ********************************************************************/
473 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
474 bool fake_dir_create_times)
478 ret = lstat(fname, &statbuf);
480 /* we always want directories to appear zero size */
481 if (S_ISDIR(statbuf.st_mode)) {
484 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
489 /*******************************************************************
490 An posix_fallocate() wrapper.
491 ********************************************************************/
492 int sys_posix_fallocate(int fd, off_t offset, off_t len)
494 #if defined(HAVE_POSIX_FALLOCATE)
495 return posix_fallocate(fd, offset, len);
496 #elif defined(F_RESVSP64)
497 /* this handles XFS on IRIX */
499 off_t new_len = offset + len;
503 /* unlikely to get a too large file on a 64bit system but ... */
507 fl.l_whence = SEEK_SET;
511 ret=fcntl(fd, F_RESVSP64, &fl);
516 /* Make sure the file gets enlarged after we allocated space: */
518 if (new_len > sbuf.st_size)
519 ftruncate64(fd, new_len);
526 /*******************************************************************
527 An fallocate() function that matches the semantics of the Linux one.
528 ********************************************************************/
530 #ifdef HAVE_LINUX_FALLOC_H
531 #include <linux/falloc.h>
534 int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len)
536 #if defined(HAVE_LINUX_FALLOCATE)
539 if (mode & VFS_FALLOCATE_FL_KEEP_SIZE) {
540 lmode |= FALLOC_FL_KEEP_SIZE;
541 mode &= ~VFS_FALLOCATE_FL_KEEP_SIZE;
544 #if defined(HAVE_FALLOC_FL_PUNCH_HOLE)
545 if (mode & VFS_FALLOCATE_FL_PUNCH_HOLE) {
546 lmode |= FALLOC_FL_PUNCH_HOLE;
547 mode &= ~VFS_FALLOCATE_FL_PUNCH_HOLE;
549 #endif /* HAVE_FALLOC_FL_PUNCH_HOLE */
552 DEBUG(2, ("unmapped fallocate flags: %lx\n",
553 (unsigned long)mode));
557 return fallocate(fd, lmode, offset, len);
558 #else /* HAVE_LINUX_FALLOCATE */
559 /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
562 #endif /* HAVE_LINUX_FALLOCATE */
565 #ifdef HAVE_KERNEL_SHARE_MODES
567 #define LOCK_MAND 32 /* This is a mandatory flock */
568 #define LOCK_READ 64 /* ... Which allows concurrent read operations */
569 #define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
570 #define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
574 /*******************************************************************
575 A flock() wrapper that will perform the kernel flock.
576 ********************************************************************/
578 void kernel_flock(int fd, uint32_t share_mode, uint32_t access_mask)
580 #ifdef HAVE_KERNEL_SHARE_MODES
582 if (share_mode == FILE_SHARE_WRITE) {
583 kernel_mode = LOCK_MAND|LOCK_WRITE;
584 } else if (share_mode == FILE_SHARE_READ) {
585 kernel_mode = LOCK_MAND|LOCK_READ;
586 } else if (share_mode == FILE_SHARE_NONE) {
587 kernel_mode = LOCK_MAND;
590 flock(fd, kernel_mode);
598 /*******************************************************************
599 An fdopendir wrapper.
600 ********************************************************************/
602 DIR *sys_fdopendir(int fd)
604 #if defined(HAVE_FDOPENDIR)
605 return fdopendir(fd);
612 /*******************************************************************
614 ********************************************************************/
616 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
618 #if defined(HAVE_MKNOD)
619 return mknod(path, mode, dev);
621 /* No mknod system call. */
627 /*******************************************************************
629 ********************************************************************/
631 int sys_mknodat(int dirfd, const char *path, mode_t mode, SMB_DEV_T dev)
633 #if defined(HAVE_MKNODAT)
634 return mknodat(dirfd, path, mode, dev);
636 /* No mknod system call. */
642 /*******************************************************************
643 System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
644 on error (malloc fail usually).
645 ********************************************************************/
647 char *sys_getwd(void)
649 #ifdef GETCWD_TAKES_NULL
650 return getcwd(NULL, 0);
651 #elif defined(HAVE_GETCWD)
652 char *wd = NULL, *s = NULL;
653 size_t allocated = PATH_MAX;
656 s = SMB_REALLOC_ARRAY(s, char, allocated);
660 wd = getcwd(s, allocated);
664 if (errno != ERANGE) {
665 int saved_errno = errno;
671 if (allocated < PATH_MAX) {
679 char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
685 int saved_errno = errno;
693 #if defined(HAVE_POSIX_CAPABILITIES)
695 /**************************************************************************
696 Try and abstract process capabilities (for systems that have them).
697 ****************************************************************************/
699 /* Set the POSIX capabilities needed for the given purpose into the effective
700 * capability set of the current process. Make sure they are always removed
701 * from the inheritable set, because there is no circumstance in which our
702 * children should inherit our elevated privileges.
704 static bool set_process_capability(enum smbd_capability capability,
707 cap_value_t cap_vals[2] = {0};
708 int num_cap_vals = 0;
712 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
713 /* On Linux, make sure that any capabilities we grab are sticky
714 * across UID changes. We expect that this would allow us to keep both
715 * the effective and permitted capability sets, but as of circa 2.6.16,
716 * only the permitted set is kept. It is a bug (which we work around)
717 * that the effective set is lost, but we still require the effective
720 if (!prctl(PR_GET_KEEPCAPS)) {
721 prctl(PR_SET_KEEPCAPS, 1);
725 cap = cap_get_proc();
727 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
732 switch (capability) {
733 case KERNEL_OPLOCK_CAPABILITY:
734 #ifdef CAP_NETWORK_MGT
735 /* IRIX has CAP_NETWORK_MGT for oplocks. */
736 cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
739 case DMAPI_ACCESS_CAPABILITY:
740 #ifdef CAP_DEVICE_MGT
741 /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
742 cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
744 /* Linux has CAP_MKNOD for DMAPI access. */
745 cap_vals[num_cap_vals++] = CAP_MKNOD;
748 case LEASE_CAPABILITY:
750 cap_vals[num_cap_vals++] = CAP_LEASE;
753 case DAC_OVERRIDE_CAPABILITY:
754 #ifdef CAP_DAC_OVERRIDE
755 cap_vals[num_cap_vals++] = CAP_DAC_OVERRIDE;
759 SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
761 if (num_cap_vals == 0) {
766 cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
767 enable ? CAP_SET : CAP_CLEAR);
769 /* We never want to pass capabilities down to our children, so make
770 * sure they are not inherited.
772 cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
774 if (cap_set_proc(cap) == -1) {
775 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
785 #endif /* HAVE_POSIX_CAPABILITIES */
787 /****************************************************************************
788 Gain the oplock capability from the kernel if possible.
789 ****************************************************************************/
791 void set_effective_capability(enum smbd_capability capability)
793 #if defined(HAVE_POSIX_CAPABILITIES)
794 set_process_capability(capability, True);
795 #endif /* HAVE_POSIX_CAPABILITIES */
798 void drop_effective_capability(enum smbd_capability capability)
800 #if defined(HAVE_POSIX_CAPABILITIES)
801 set_process_capability(capability, False);
802 #endif /* HAVE_POSIX_CAPABILITIES */
805 /**************************************************************************
806 Wrapper for random().
807 ****************************************************************************/
809 long sys_random(void)
811 #if defined(HAVE_RANDOM)
812 return (long)random();
813 #elif defined(HAVE_RAND)
816 DEBUG(0,("Error - no random function available !\n"));
821 /**************************************************************************
822 Wrapper for srandom().
823 ****************************************************************************/
825 void sys_srandom(unsigned int seed)
827 #if defined(HAVE_SRANDOM)
829 #elif defined(HAVE_SRAND)
832 DEBUG(0,("Error - no srandom function available !\n"));
838 #define NGROUPS_MAX 32 /* Guess... */
841 /**************************************************************************
842 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
843 ****************************************************************************/
847 #if defined(SYSCONF_SC_NGROUPS_MAX)
848 int ret = sysconf(_SC_NGROUPS_MAX);
849 return (ret == -1) ? NGROUPS_MAX : ret;
855 /**************************************************************************
856 Wrap setgroups and getgroups for systems that declare getgroups() as
857 returning an array of gid_t, but actuall return an array of int.
858 ****************************************************************************/
860 #if defined(HAVE_BROKEN_GETGROUPS)
862 #ifdef HAVE_BROKEN_GETGROUPS
868 static int sys_broken_getgroups(int setlen, gid_t *gidset)
874 return getgroups(0, NULL);
878 * Broken case. We need to allocate a
879 * GID_T array of size setlen.
887 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
888 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
892 if((ngroups = getgroups(setlen, group_list)) < 0) {
893 int saved_errno = errno;
894 SAFE_FREE(group_list);
900 * We're safe here as if ngroups > setlen then
901 * getgroups *must* return EINVAL.
902 * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
905 for(i = 0; i < ngroups; i++)
906 gidset[i] = (gid_t)group_list[i];
908 SAFE_FREE(group_list);
912 static int sys_broken_setgroups(int setlen, gid_t *gidset)
920 if (setlen < 0 || setlen > groups_max()) {
926 * Broken case. We need to allocate a
927 * GID_T array of size setlen.
930 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
931 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
935 for(i = 0; i < setlen; i++)
936 group_list[i] = (GID_T) gidset[i];
938 if(samba_setgroups(setlen, group_list) != 0) {
939 int saved_errno = errno;
940 SAFE_FREE(group_list);
945 SAFE_FREE(group_list);
949 #endif /* HAVE_BROKEN_GETGROUPS */
951 /* This is a list of systems that require the first GID passed to setgroups(2)
952 * to be the effective GID. If your system is one of these, add it here.
954 #if defined (FREEBSD) || defined (DARWINOS)
955 #define USE_BSD_SETGROUPS
958 #if defined(USE_BSD_SETGROUPS)
959 /* Depending on the particular BSD implementation, the first GID that is
960 * passed to setgroups(2) will either be ignored or will set the credential's
961 * effective GID. In either case, the right thing to do is to guarantee that
962 * gidset[0] is the effective GID.
964 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
966 gid_t *new_gidset = NULL;
970 /* setgroups(2) will fail with EINVAL if we pass too many groups. */
973 /* No group list, just make sure we are setting the efective GID. */
975 return samba_setgroups(1, &primary_gid);
978 /* If the primary gid is not the first array element, grow the array
979 * and insert it at the front.
981 if (gidset[0] != primary_gid) {
982 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
983 if (new_gidset == NULL) {
987 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
988 new_gidset[0] = primary_gid;
993 DEBUG(3, ("forced to truncate group list from %d to %d\n",
998 #if defined(HAVE_BROKEN_GETGROUPS)
999 ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1001 ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
1006 SAFE_FREE(new_gidset);
1013 #endif /* USE_BSD_SETGROUPS */
1015 /**************************************************************************
1016 Wrapper for getgroups. Deals with broken (int) case.
1017 ****************************************************************************/
1019 int sys_getgroups(int setlen, gid_t *gidset)
1021 #if defined(HAVE_BROKEN_GETGROUPS)
1022 return sys_broken_getgroups(setlen, gidset);
1024 return getgroups(setlen, gidset);
1028 /**************************************************************************
1029 Wrapper for setgroups. Deals with broken (int) case and BSD case.
1030 ****************************************************************************/
1032 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1034 #if !defined(HAVE_SETGROUPS)
1037 #endif /* HAVE_SETGROUPS */
1039 #if defined(USE_BSD_SETGROUPS)
1040 return sys_bsd_setgroups(primary_gid, setlen, gidset);
1041 #elif defined(HAVE_BROKEN_GETGROUPS)
1042 return sys_broken_setgroups(setlen, gidset);
1044 return samba_setgroups(setlen, gidset);
1048 /****************************************************************************
1049 Return the major devicenumber for UNIX extensions.
1050 ****************************************************************************/
1052 uint32_t unix_dev_major(SMB_DEV_T dev)
1054 #if defined(HAVE_DEVICE_MAJOR_FN)
1055 return (uint32_t)major(dev);
1057 return (uint32_t)(dev >> 8);
1061 /****************************************************************************
1062 Return the minor devicenumber for UNIX extensions.
1063 ****************************************************************************/
1065 uint32_t unix_dev_minor(SMB_DEV_T dev)
1067 #if defined(HAVE_DEVICE_MINOR_FN)
1068 return (uint32_t)minor(dev);
1070 return (uint32_t)(dev & 0xff);
1074 /**************************************************************************
1075 Wrapper for realpath.
1076 ****************************************************************************/
1078 char *sys_realpath(const char *path)
1082 #ifdef REALPATH_TAKES_NULL
1083 result = realpath(path, NULL);
1085 result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
1087 char *resolved_path = realpath(path, result);
1088 if (!resolved_path) {
1091 /* SMB_ASSERT(result == resolved_path) ? */
1092 result = resolved_path;
1100 /*******************************************************************
1101 Return the number of CPUs.
1102 ********************************************************************/
1104 int sys_get_number_of_cores(void)
1108 #if defined(HAVE_SYSCONF)
1109 #if defined(_SC_NPROCESSORS_ONLN)
1110 ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
1112 #if defined(_SC_NPROCESSORS_CONF)
1114 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
1117 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
1119 unsigned int len = sizeof(ret);
1122 #if defined(HW_AVAILCPU)
1123 name[1] = HW_AVAILCPU;
1125 if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
1129 #if defined(HW_NCPU)
1133 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {