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"
29 #include "lib/util/time.h"
31 #ifdef HAVE_SYS_SYSCTL_H
32 #include <sys/sysctl.h>
35 #ifdef HAVE_SYS_PRCTL_H
36 #include <sys/prctl.h>
40 The idea is that this file will eventually have wrappers around all
41 important system calls in samba. The aims are:
43 - to enable easier porting by putting OS dependent stuff in here
45 - to allow for hooks into other "pseudo-filesystems"
47 - to allow easier integration of things like the japanese extensions
49 - to support the philosophy of Samba to expose the features of
50 the OS within the SMB model. In general whatever file/printer/variable
51 expansions/etc make sense to the OS should be acceptable to Samba.
54 /*******************************************************************
55 A send wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK.
56 ********************************************************************/
58 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
63 ret = send(s, msg, len, flags);
64 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
69 /*******************************************************************
70 A recvfrom wrapper that will deal with EINTR.
71 NB. As used with non-blocking sockets, return on EAGAIN/EWOULDBLOCK
72 ********************************************************************/
74 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
79 ret = recvfrom(s, buf, len, flags, from, fromlen);
80 } while (ret == -1 && (errno == EINTR));
84 /*******************************************************************
85 A fcntl wrapper that will deal with EINTR.
86 ********************************************************************/
88 int sys_fcntl_ptr(int fd, int cmd, void *arg)
93 ret = fcntl(fd, cmd, arg);
94 } while (ret == -1 && errno == EINTR);
98 /*******************************************************************
99 A fcntl wrapper that will deal with EINTR.
100 ********************************************************************/
102 int sys_fcntl_long(int fd, int cmd, long arg)
107 ret = fcntl(fd, cmd, arg);
108 } while (ret == -1 && errno == EINTR);
112 /*******************************************************************
113 A fcntl wrapper that will deal with EINTR.
114 ********************************************************************/
116 int sys_fcntl_int(int fd, int cmd, int arg)
121 ret = fcntl(fd, cmd, arg);
122 } while (ret == -1 && errno == EINTR);
126 /****************************************************************************
127 Return the best approximation to a 'create time' under UNIX from a stat
129 ****************************************************************************/
131 static struct timespec calc_create_time_stat(const struct stat *st)
133 struct timespec ret, ret1;
134 struct timespec c_time = get_ctimespec(st);
135 struct timespec m_time = get_mtimespec(st);
136 struct timespec a_time = get_atimespec(st);
138 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
139 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
141 if(!null_timespec(ret1)) {
146 * One of ctime, mtime or atime was zero (probably atime).
147 * Just return MIN(ctime, mtime).
152 /****************************************************************************
153 Return the best approximation to a 'create time' under UNIX from a stat_ex
155 ****************************************************************************/
157 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
159 struct timespec ret, ret1;
160 struct timespec c_time = st->st_ex_ctime;
161 struct timespec m_time = st->st_ex_mtime;
162 struct timespec a_time = st->st_ex_atime;
164 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
165 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
167 if(!null_timespec(ret1)) {
172 * One of ctime, mtime or atime was zero (probably atime).
173 * Just return MIN(ctime, mtime).
178 /****************************************************************************
179 Return the 'create time' from a stat struct if it exists (birthtime) or else
180 use the best approximation.
181 ****************************************************************************/
183 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
184 bool fake_dir_create_times)
186 if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
187 dst->st_ex_btime.tv_sec = 315493200L; /* 1/1/1980 */
188 dst->st_ex_btime.tv_nsec = 0;
191 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
193 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
194 dst->st_ex_btime = pst->st_birthtimespec;
195 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
196 dst->st_ex_btime.tv_sec = pst->st_birthtime;
197 dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
198 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
199 dst->st_ex_btime.tv_sec = pst->st_birthtime;
200 dst->st_ex_btime.tv_nsec = 0;
202 dst->st_ex_btime = calc_create_time_stat(pst);
203 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
206 /* Deal with systems that don't initialize birthtime correctly.
207 * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
209 if (null_timespec(dst->st_ex_btime)) {
210 dst->st_ex_btime = calc_create_time_stat(pst);
211 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
214 dst->st_ex_itime = dst->st_ex_btime;
215 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_ITIME;
218 /****************************************************************************
219 If we update a timestamp in a stat_ex struct we may have to recalculate
220 the birthtime. For now only implement this for write time, but we may
221 also need to do it for atime and ctime. JRA.
222 ****************************************************************************/
224 void update_stat_ex_mtime(struct stat_ex *dst,
225 struct timespec write_ts)
227 dst->st_ex_mtime = write_ts;
229 /* We may have to recalculate btime. */
230 if (dst->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME) {
231 dst->st_ex_btime = calc_create_time_stat_ex(dst);
235 void update_stat_ex_create_time(struct stat_ex *dst,
236 struct timespec create_time)
238 dst->st_ex_btime = create_time;
239 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
242 void update_stat_ex_itime(struct stat_ex *dst,
243 struct timespec itime)
245 dst->st_ex_itime = itime;
246 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME;
249 void update_stat_ex_file_id(struct stat_ex *dst, uint64_t file_id)
251 dst->st_ex_file_id = file_id;
252 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_FILE_ID;
255 void update_stat_ex_from_saved_stat(struct stat_ex *dst,
256 const struct stat_ex *src)
258 if (!VALID_STAT(*src)) {
262 if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME)) {
263 update_stat_ex_create_time(dst, src->st_ex_btime);
266 if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
267 update_stat_ex_itime(dst, src->st_ex_itime);
270 if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
271 update_stat_ex_file_id(dst, src->st_ex_file_id);
275 void init_stat_ex_from_stat (struct stat_ex *dst,
276 const struct stat *src,
277 bool fake_dir_create_times)
279 dst->st_ex_dev = src->st_dev;
280 dst->st_ex_ino = src->st_ino;
281 dst->st_ex_mode = src->st_mode;
282 dst->st_ex_nlink = src->st_nlink;
283 dst->st_ex_uid = src->st_uid;
284 dst->st_ex_gid = src->st_gid;
285 dst->st_ex_rdev = src->st_rdev;
286 dst->st_ex_size = src->st_size;
287 dst->st_ex_atime = get_atimespec(src);
288 dst->st_ex_mtime = get_mtimespec(src);
289 dst->st_ex_ctime = get_ctimespec(src);
290 dst->st_ex_iflags = 0;
291 make_create_timespec(src, dst, fake_dir_create_times);
292 #ifdef HAVE_STAT_ST_BLKSIZE
293 dst->st_ex_blksize = src->st_blksize;
295 dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
298 #ifdef HAVE_STAT_ST_BLOCKS
299 dst->st_ex_blocks = src->st_blocks;
301 dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
304 #ifdef HAVE_STAT_ST_FLAGS
305 dst->st_ex_flags = src->st_flags;
307 dst->st_ex_flags = 0;
309 dst->st_ex_file_id = dst->st_ex_ino;
310 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_FILE_ID;
313 /*******************************************************************
314 Create a clock-derived itime (invented) time. Used to generate
316 ********************************************************************/
318 void create_clock_itime(struct stat_ex *dst)
321 struct timespec itime;
325 /* Start with the system clock. */
326 itime = timespec_current();
328 /* Convert to NTTIME. */
329 tval = unix_timespec_to_nt_time(itime);
332 * In case the system clock is poor granularity
333 * (happens on VM or docker images) then mix in
334 * 8 bits of randomness.
336 generate_random_buffer((unsigned char *)&rval, 1);
340 * Shift up by 55 bits. This gives us approx 114 years
345 /* And OR into the nttime. */
349 * Convert to a unix timespec, ignoring any
350 * constraints on seconds being higher than
351 * TIME_T_MAX or lower than TIME_T_MIN. These
352 * are only needed to allow unix display time functions
353 * to work correctly, and this is being used to
354 * generate a fileid. All we care about is the
355 * NTTIME being valid across all NTTIME ranges
356 * (which we carefully ensured above).
359 itime = nt_time_to_unix_timespec_raw(tval);
361 /* And set as a generated itime. */
362 update_stat_ex_itime(dst, itime);
365 /*******************************************************************
367 ********************************************************************/
369 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
370 bool fake_dir_create_times)
374 ret = stat(fname, &statbuf);
376 /* we always want directories to appear zero size */
377 if (S_ISDIR(statbuf.st_mode)) {
380 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
385 /*******************************************************************
387 ********************************************************************/
389 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
393 ret = fstat(fd, &statbuf);
395 /* we always want directories to appear zero size */
396 if (S_ISDIR(statbuf.st_mode)) {
399 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
404 /*******************************************************************
406 ********************************************************************/
408 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
409 bool fake_dir_create_times)
413 ret = lstat(fname, &statbuf);
415 /* we always want directories to appear zero size */
416 if (S_ISDIR(statbuf.st_mode)) {
419 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
424 /*******************************************************************
425 An fstatat() wrapper.
426 ********************************************************************/
428 int sys_fstatat(int fd,
429 const char *pathname,
430 SMB_STRUCT_STAT *sbuf,
432 bool fake_dir_create_times)
437 ret = fstatat(fd, pathname, &statbuf, flags);
442 /* we always want directories to appear zero size */
443 if (S_ISDIR(statbuf.st_mode)) {
446 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
450 /*******************************************************************
451 An posix_fallocate() wrapper.
452 ********************************************************************/
453 int sys_posix_fallocate(int fd, off_t offset, off_t len)
455 #if defined(HAVE_POSIX_FALLOCATE)
456 return posix_fallocate(fd, offset, len);
457 #elif defined(F_RESVSP64)
458 /* this handles XFS on IRIX */
460 off_t new_len = offset + len;
464 /* unlikely to get a too large file on a 64bit system but ... */
468 fl.l_whence = SEEK_SET;
472 ret=fcntl(fd, F_RESVSP64, &fl);
477 /* Make sure the file gets enlarged after we allocated space: */
479 if (new_len > sbuf.st_size)
480 ftruncate64(fd, new_len);
487 /*******************************************************************
488 An fallocate() function that matches the semantics of the Linux one.
489 ********************************************************************/
491 #ifdef HAVE_LINUX_FALLOC_H
492 #include <linux/falloc.h>
495 int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len)
497 #if defined(HAVE_LINUX_FALLOCATE)
500 if (mode & VFS_FALLOCATE_FL_KEEP_SIZE) {
501 lmode |= FALLOC_FL_KEEP_SIZE;
502 mode &= ~VFS_FALLOCATE_FL_KEEP_SIZE;
505 #if defined(HAVE_FALLOC_FL_PUNCH_HOLE)
506 if (mode & VFS_FALLOCATE_FL_PUNCH_HOLE) {
507 lmode |= FALLOC_FL_PUNCH_HOLE;
508 mode &= ~VFS_FALLOCATE_FL_PUNCH_HOLE;
510 #endif /* HAVE_FALLOC_FL_PUNCH_HOLE */
513 DEBUG(2, ("unmapped fallocate flags: %lx\n",
514 (unsigned long)mode));
518 return fallocate(fd, lmode, offset, len);
519 #else /* HAVE_LINUX_FALLOCATE */
520 /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
523 #endif /* HAVE_LINUX_FALLOCATE */
526 /*******************************************************************
527 An fdopendir wrapper.
528 ********************************************************************/
530 DIR *sys_fdopendir(int fd)
532 #if defined(HAVE_FDOPENDIR)
533 return fdopendir(fd);
540 /*******************************************************************
542 ********************************************************************/
544 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
546 #if defined(HAVE_MKNOD)
547 return mknod(path, mode, dev);
549 /* No mknod system call. */
555 /*******************************************************************
557 ********************************************************************/
559 int sys_mknodat(int dirfd, const char *path, mode_t mode, SMB_DEV_T dev)
561 #if defined(HAVE_MKNODAT)
562 return mknodat(dirfd, path, mode, dev);
564 /* No mknod system call. */
570 /*******************************************************************
571 System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
572 on error (malloc fail usually).
573 ********************************************************************/
575 char *sys_getwd(void)
577 #ifdef GETCWD_TAKES_NULL
578 return getcwd(NULL, 0);
579 #elif defined(HAVE_GETCWD)
580 char *wd = NULL, *s = NULL;
581 size_t allocated = PATH_MAX;
584 s = SMB_REALLOC_ARRAY(s, char, allocated);
588 wd = getcwd(s, allocated);
592 if (errno != ERANGE) {
593 int saved_errno = errno;
599 if (allocated < PATH_MAX) {
607 char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
613 int saved_errno = errno;
621 #if defined(HAVE_POSIX_CAPABILITIES)
623 /**************************************************************************
624 Try and abstract process capabilities (for systems that have them).
625 ****************************************************************************/
627 /* Set the POSIX capabilities needed for the given purpose into the effective
628 * capability set of the current process. Make sure they are always removed
629 * from the inheritable set, because there is no circumstance in which our
630 * children should inherit our elevated privileges.
632 static bool set_process_capability(enum smbd_capability capability,
635 /* "5" is the number of "num_cap_vals++" below */
636 cap_value_t cap_vals[5] = {0};
637 size_t num_cap_vals = 0;
641 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
642 /* On Linux, make sure that any capabilities we grab are sticky
643 * across UID changes. We expect that this would allow us to keep both
644 * the effective and permitted capability sets, but as of circa 2.6.16,
645 * only the permitted set is kept. It is a bug (which we work around)
646 * that the effective set is lost, but we still require the effective
649 if (!prctl(PR_GET_KEEPCAPS)) {
650 prctl(PR_SET_KEEPCAPS, 1);
654 cap = cap_get_proc();
656 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
661 switch (capability) {
663 * WARNING: If you add any #ifdef for a fresh
664 * capability, bump up the array size in the
665 * declaration of cap_vals[] above just to be
666 * trivially safe to never overwrite cap_vals[].
668 case KERNEL_OPLOCK_CAPABILITY:
669 #ifdef CAP_NETWORK_MGT
670 /* IRIX has CAP_NETWORK_MGT for oplocks. */
671 cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
674 case DMAPI_ACCESS_CAPABILITY:
675 #ifdef CAP_DEVICE_MGT
676 /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
677 cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
679 /* Linux has CAP_MKNOD for DMAPI access. */
680 cap_vals[num_cap_vals++] = CAP_MKNOD;
683 case LEASE_CAPABILITY:
685 cap_vals[num_cap_vals++] = CAP_LEASE;
688 case DAC_OVERRIDE_CAPABILITY:
689 #ifdef CAP_DAC_OVERRIDE
690 cap_vals[num_cap_vals++] = CAP_DAC_OVERRIDE;
694 if (num_cap_vals == 0) {
699 cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
700 enable ? CAP_SET : CAP_CLEAR);
702 /* We never want to pass capabilities down to our children, so make
703 * sure they are not inherited.
705 cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
707 if (cap_set_proc(cap) == -1) {
708 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
718 #endif /* HAVE_POSIX_CAPABILITIES */
720 /****************************************************************************
721 Gain the oplock capability from the kernel if possible.
722 ****************************************************************************/
724 void set_effective_capability(enum smbd_capability capability)
726 #if defined(HAVE_POSIX_CAPABILITIES)
727 set_process_capability(capability, True);
728 #endif /* HAVE_POSIX_CAPABILITIES */
731 void drop_effective_capability(enum smbd_capability capability)
733 #if defined(HAVE_POSIX_CAPABILITIES)
734 set_process_capability(capability, False);
735 #endif /* HAVE_POSIX_CAPABILITIES */
738 /**************************************************************************
739 Wrapper for random().
740 ****************************************************************************/
742 long sys_random(void)
744 #if defined(HAVE_RANDOM)
745 return (long)random();
746 #elif defined(HAVE_RAND)
749 DEBUG(0,("Error - no random function available !\n"));
754 /**************************************************************************
755 Wrapper for srandom().
756 ****************************************************************************/
758 void sys_srandom(unsigned int seed)
760 #if defined(HAVE_SRANDOM)
762 #elif defined(HAVE_SRAND)
765 DEBUG(0,("Error - no srandom function available !\n"));
771 #define NGROUPS_MAX 32 /* Guess... */
774 /**************************************************************************
775 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
776 ****************************************************************************/
778 int setgroups_max(void)
780 #if defined(SYSCONF_SC_NGROUPS_MAX)
781 int ret = sysconf(_SC_NGROUPS_MAX);
782 return (ret == -1) ? NGROUPS_MAX : ret;
788 int getgroups_max(void)
790 #if defined(DARWINOS)
792 * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group
793 * nesting. However, The initgroups() manpage states the following:
794 * "Note that OS X supports group membership in an unlimited number
795 * of groups. The OS X kernel uses the group list stored in the process
796 * credentials only as an initial cache. Additional group memberships
797 * are determined by communication between the operating system and the
798 * opendirectoryd daemon."
802 return setgroups_max();
806 /**************************************************************************
807 Wrap setgroups and getgroups for systems that declare getgroups() as
808 returning an array of gid_t, but actuall return an array of int.
809 ****************************************************************************/
811 #if defined(HAVE_BROKEN_GETGROUPS)
813 #ifdef HAVE_BROKEN_GETGROUPS
819 static int sys_broken_getgroups(int setlen, gid_t *gidset)
825 return getgroups(0, NULL);
829 * Broken case. We need to allocate a
830 * GID_T array of size setlen.
838 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
839 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
843 if((ngroups = getgroups(setlen, group_list)) < 0) {
844 int saved_errno = errno;
845 SAFE_FREE(group_list);
851 * We're safe here as if ngroups > setlen then
852 * getgroups *must* return EINVAL.
853 * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
856 for(i = 0; i < ngroups; i++)
857 gidset[i] = (gid_t)group_list[i];
859 SAFE_FREE(group_list);
863 static int sys_broken_setgroups(int setlen, gid_t *gidset)
871 if (setlen < 0 || setlen > setgroups_max()) {
877 * Broken case. We need to allocate a
878 * GID_T array of size setlen.
881 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
882 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
886 for(i = 0; i < setlen; i++)
887 group_list[i] = (GID_T) gidset[i];
889 if(samba_setgroups(setlen, group_list) != 0) {
890 int saved_errno = errno;
891 SAFE_FREE(group_list);
896 SAFE_FREE(group_list);
900 #endif /* HAVE_BROKEN_GETGROUPS */
902 /* This is a list of systems that require the first GID passed to setgroups(2)
903 * to be the effective GID. If your system is one of these, add it here.
905 #if defined (FREEBSD) || defined (DARWINOS)
906 #define USE_BSD_SETGROUPS
909 #if defined(USE_BSD_SETGROUPS)
910 /* Depending on the particular BSD implementation, the first GID that is
911 * passed to setgroups(2) will either be ignored or will set the credential's
912 * effective GID. In either case, the right thing to do is to guarantee that
913 * gidset[0] is the effective GID.
915 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
917 gid_t *new_gidset = NULL;
921 /* setgroups(2) will fail with EINVAL if we pass too many groups. */
922 max = setgroups_max();
924 /* No group list, just make sure we are setting the efective GID. */
926 return samba_setgroups(1, &primary_gid);
929 /* If the primary gid is not the first array element, grow the array
930 * and insert it at the front.
932 if (gidset[0] != primary_gid) {
933 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
934 if (new_gidset == NULL) {
938 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
939 new_gidset[0] = primary_gid;
944 DEBUG(3, ("forced to truncate group list from %d to %d\n",
949 #if defined(HAVE_BROKEN_GETGROUPS)
950 ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
952 ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
957 SAFE_FREE(new_gidset);
964 #endif /* USE_BSD_SETGROUPS */
966 /**************************************************************************
967 Wrapper for getgroups. Deals with broken (int) case.
968 ****************************************************************************/
970 int sys_getgroups(int setlen, gid_t *gidset)
972 #if defined(HAVE_BROKEN_GETGROUPS)
973 return sys_broken_getgroups(setlen, gidset);
975 return getgroups(setlen, gidset);
979 /**************************************************************************
980 Wrapper for setgroups. Deals with broken (int) case and BSD case.
981 ****************************************************************************/
983 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
985 #if !defined(HAVE_SETGROUPS)
988 #endif /* HAVE_SETGROUPS */
990 #if defined(USE_BSD_SETGROUPS)
991 return sys_bsd_setgroups(primary_gid, setlen, gidset);
992 #elif defined(HAVE_BROKEN_GETGROUPS)
993 return sys_broken_setgroups(setlen, gidset);
995 return samba_setgroups(setlen, gidset);
999 /****************************************************************************
1000 Return the major devicenumber for UNIX extensions.
1001 ****************************************************************************/
1003 uint32_t unix_dev_major(SMB_DEV_T dev)
1005 #if defined(HAVE_DEVICE_MAJOR_FN)
1006 return (uint32_t)major(dev);
1008 return (uint32_t)(dev >> 8);
1012 /****************************************************************************
1013 Return the minor devicenumber for UNIX extensions.
1014 ****************************************************************************/
1016 uint32_t unix_dev_minor(SMB_DEV_T dev)
1018 #if defined(HAVE_DEVICE_MINOR_FN)
1019 return (uint32_t)minor(dev);
1021 return (uint32_t)(dev & 0xff);
1025 /**************************************************************************
1026 Wrapper for realpath.
1027 ****************************************************************************/
1029 char *sys_realpath(const char *path)
1033 #ifdef REALPATH_TAKES_NULL
1034 result = realpath(path, NULL);
1036 result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
1038 char *resolved_path = realpath(path, result);
1039 if (!resolved_path) {
1042 /* SMB_ASSERT(result == resolved_path) ? */
1043 result = resolved_path;
1051 /*******************************************************************
1052 Return the number of CPUs.
1053 ********************************************************************/
1055 int sys_get_number_of_cores(void)
1059 #if defined(HAVE_SYSCONF)
1060 #if defined(_SC_NPROCESSORS_ONLN)
1061 ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
1063 #if defined(_SC_NPROCESSORS_CONF)
1065 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
1068 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
1070 unsigned int len = sizeof(ret);
1073 #if defined(HW_AVAILCPU)
1074 name[1] = HW_AVAILCPU;
1076 if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
1080 #if defined(HW_NCPU)
1084 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
1097 static struct proc_fd_pattern {
1098 const char *pattern;
1099 const char *test_path;
1100 } proc_fd_patterns[] = {
1102 { "/proc/self/fd/%d", "/proc/self/fd/0" },
1106 static const char *proc_fd_pattern;
1108 bool sys_have_proc_fds(void)
1110 static bool checked;
1111 static bool have_proc_fds;
1112 struct proc_fd_pattern *p = NULL;
1117 return have_proc_fds;
1120 for (p = &proc_fd_patterns[0]; p->test_path != NULL; p++) {
1121 ret = stat(p->test_path, &sb);
1125 have_proc_fds = true;
1126 proc_fd_pattern = p->pattern;
1131 return have_proc_fds;
1134 const char *sys_proc_fd_path(int fd, char *buf, size_t bufsize)
1138 if (!sys_have_proc_fds()) {
1142 #if defined(__clang__)
1143 #pragma clang diagnostic push
1144 #pragma clang diagnostic ignored "-Wformat-nonliteral"
1146 written = snprintf(buf,
1150 #if defined(__clang__)
1151 #pragma clang diagnostic pop
1153 if (written >= bufsize) {