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;
192 dst
->st_ex_iflags
&= ~ST_EX_IFLAG_CALCULATED_BTIME
;
194 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
195 dst
->st_ex_btime
= pst
->st_birthtimespec
;
196 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
197 dst
->st_ex_btime
.tv_sec
= pst
->st_birthtime
;
198 dst
->st_ex_btime
.tv_nsec
= pst
->st_birthtimenspec
;
199 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
200 dst
->st_ex_btime
.tv_sec
= pst
->st_birthtime
;
201 dst
->st_ex_btime
.tv_nsec
= 0;
203 dst
->st_ex_btime
= calc_create_time_stat(pst
);
204 dst
->st_ex_iflags
|= ST_EX_IFLAG_CALCULATED_BTIME
;
207 /* Deal with systems that don't initialize birthtime correctly.
208 * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
210 if (null_timespec(dst
->st_ex_btime
)) {
211 dst
->st_ex_btime
= calc_create_time_stat(pst
);
212 dst
->st_ex_iflags
|= ST_EX_IFLAG_CALCULATED_BTIME
;
216 /****************************************************************************
217 If we update a timestamp in a stat_ex struct we may have to recalculate
218 the birthtime. For now only implement this for write time, but we may
219 also need to do it for atime and ctime. JRA.
220 ****************************************************************************/
222 void update_stat_ex_mtime(struct stat_ex
*dst
,
223 struct timespec write_ts
)
225 dst
->st_ex_mtime
= write_ts
;
227 /* We may have to recalculate btime. */
228 if (dst
->st_ex_iflags
& ST_EX_IFLAG_CALCULATED_BTIME
) {
229 dst
->st_ex_btime
= calc_create_time_stat_ex(dst
);
233 void update_stat_ex_create_time(struct stat_ex
*dst
,
234 struct timespec create_time
)
236 dst
->st_ex_btime
= create_time
;
237 dst
->st_ex_iflags
&= ~ST_EX_IFLAG_CALCULATED_BTIME
;
240 void update_stat_ex_from_saved_stat(struct stat_ex
*dst
,
241 const struct stat_ex
*src
)
243 if (!VALID_STAT(*src
)) {
247 if (!(src
->st_ex_iflags
& ST_EX_IFLAG_CALCULATED_BTIME
)) {
248 update_stat_ex_create_time(dst
, src
->st_ex_btime
);
252 void copy_stat_ex_timestamps(files_struct
*fsp
, const struct smb_file_time
*ft
)
254 if (!is_omit_timespec(&ft
->atime
)) {
255 fsp
->fsp_name
->st
.st_ex_atime
= ft
->atime
;
258 if (!is_omit_timespec(&ft
->create_time
)) {
259 fsp
->fsp_name
->st
.st_ex_btime
= ft
->create_time
;
262 if (!is_omit_timespec(&ft
->ctime
)) {
263 fsp
->fsp_name
->st
.st_ex_ctime
= ft
->ctime
;
266 if (!is_omit_timespec(&ft
->mtime
)) {
267 fsp
->fsp_name
->st
.st_ex_mtime
= ft
->mtime
;
271 void init_stat_ex_from_stat (struct stat_ex
*dst
,
272 const struct stat
*src
,
273 bool fake_dir_create_times
)
275 dst
->st_ex_dev
= src
->st_dev
;
276 dst
->st_ex_ino
= src
->st_ino
;
277 dst
->st_ex_mode
= src
->st_mode
;
278 dst
->st_ex_nlink
= src
->st_nlink
;
279 dst
->st_ex_uid
= src
->st_uid
;
280 dst
->st_ex_gid
= src
->st_gid
;
281 dst
->st_ex_rdev
= src
->st_rdev
;
282 dst
->st_ex_size
= src
->st_size
;
283 dst
->st_ex_atime
= get_atimespec(src
);
284 dst
->st_ex_mtime
= get_mtimespec(src
);
285 dst
->st_ex_ctime
= get_ctimespec(src
);
286 dst
->st_ex_iflags
= 0;
287 make_create_timespec(src
, dst
, fake_dir_create_times
);
288 #ifdef HAVE_STAT_ST_BLKSIZE
289 dst
->st_ex_blksize
= src
->st_blksize
;
291 dst
->st_ex_blksize
= STAT_ST_BLOCKSIZE
;
294 #ifdef HAVE_STAT_ST_BLOCKS
295 dst
->st_ex_blocks
= src
->st_blocks
;
297 dst
->st_ex_blocks
= src
->st_size
/ dst
->st_ex_blksize
+ 1;
300 #ifdef HAVE_STAT_ST_FLAGS
301 dst
->st_ex_flags
= src
->st_flags
;
303 dst
->st_ex_flags
= 0;
307 /*******************************************************************
309 ********************************************************************/
311 int sys_stat(const char *fname
, SMB_STRUCT_STAT
*sbuf
,
312 bool fake_dir_create_times
)
316 ret
= stat(fname
, &statbuf
);
318 /* we always want directories to appear zero size */
319 if (S_ISDIR(statbuf
.st_mode
)) {
322 init_stat_ex_from_stat(sbuf
, &statbuf
, fake_dir_create_times
);
327 /*******************************************************************
329 ********************************************************************/
331 int sys_fstat(int fd
, SMB_STRUCT_STAT
*sbuf
, bool fake_dir_create_times
)
335 ret
= fstat(fd
, &statbuf
);
337 /* we always want directories to appear zero size */
338 if (S_ISDIR(statbuf
.st_mode
)) {
341 init_stat_ex_from_stat(sbuf
, &statbuf
, fake_dir_create_times
);
346 /*******************************************************************
348 ********************************************************************/
350 int sys_lstat(const char *fname
,SMB_STRUCT_STAT
*sbuf
,
351 bool fake_dir_create_times
)
355 ret
= lstat(fname
, &statbuf
);
357 /* we always want directories to appear zero size */
358 if (S_ISDIR(statbuf
.st_mode
)) {
361 init_stat_ex_from_stat(sbuf
, &statbuf
, fake_dir_create_times
);
366 /*******************************************************************
367 An fstatat() wrapper.
368 ********************************************************************/
370 int sys_fstatat(int fd
,
371 const char *pathname
,
372 SMB_STRUCT_STAT
*sbuf
,
374 bool fake_dir_create_times
)
379 ret
= fstatat(fd
, pathname
, &statbuf
, flags
);
384 /* we always want directories to appear zero size */
385 if (S_ISDIR(statbuf
.st_mode
)) {
388 init_stat_ex_from_stat(sbuf
, &statbuf
, fake_dir_create_times
);
392 /*******************************************************************
393 An posix_fallocate() wrapper.
394 ********************************************************************/
395 int sys_posix_fallocate(int fd
, off_t offset
, off_t len
)
397 #if defined(HAVE_POSIX_FALLOCATE)
398 return posix_fallocate(fd
, offset
, len
);
399 #elif defined(F_RESVSP64)
400 /* this handles XFS on IRIX */
402 off_t new_len
= offset
+ len
;
406 /* unlikely to get a too large file on a 64bit system but ... */
410 fl
.l_whence
= SEEK_SET
;
414 ret
=fcntl(fd
, F_RESVSP64
, &fl
);
419 /* Make sure the file gets enlarged after we allocated space: */
421 if (new_len
> sbuf
.st_size
)
422 ftruncate64(fd
, new_len
);
429 /*******************************************************************
430 An fallocate() function that matches the semantics of the Linux one.
431 ********************************************************************/
433 #ifdef HAVE_LINUX_FALLOC_H
434 #include <linux/falloc.h>
437 int sys_fallocate(int fd
, uint32_t mode
, off_t offset
, off_t len
)
439 #if defined(HAVE_LINUX_FALLOCATE)
442 if (mode
& VFS_FALLOCATE_FL_KEEP_SIZE
) {
443 lmode
|= FALLOC_FL_KEEP_SIZE
;
444 mode
&= ~VFS_FALLOCATE_FL_KEEP_SIZE
;
447 #if defined(HAVE_FALLOC_FL_PUNCH_HOLE)
448 if (mode
& VFS_FALLOCATE_FL_PUNCH_HOLE
) {
449 lmode
|= FALLOC_FL_PUNCH_HOLE
;
450 mode
&= ~VFS_FALLOCATE_FL_PUNCH_HOLE
;
452 #endif /* HAVE_FALLOC_FL_PUNCH_HOLE */
455 DEBUG(2, ("unmapped fallocate flags: %lx\n",
456 (unsigned long)mode
));
460 return fallocate(fd
, lmode
, offset
, len
);
461 #else /* HAVE_LINUX_FALLOCATE */
462 /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
465 #endif /* HAVE_LINUX_FALLOCATE */
468 /*******************************************************************
469 An fdopendir wrapper.
470 ********************************************************************/
472 DIR *sys_fdopendir(int fd
)
474 #if defined(HAVE_FDOPENDIR)
475 return fdopendir(fd
);
482 /*******************************************************************
484 ********************************************************************/
486 int sys_mknod(const char *path
, mode_t mode
, SMB_DEV_T dev
)
488 #if defined(HAVE_MKNOD)
489 return mknod(path
, mode
, dev
);
491 /* No mknod system call. */
497 /*******************************************************************
499 ********************************************************************/
501 int sys_mknodat(int dirfd
, const char *path
, mode_t mode
, SMB_DEV_T dev
)
503 #if defined(HAVE_MKNODAT)
504 return mknodat(dirfd
, path
, mode
, dev
);
506 /* No mknod system call. */
512 /*******************************************************************
513 System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
514 on error (malloc fail usually).
515 ********************************************************************/
517 char *sys_getwd(void)
519 #ifdef GETCWD_TAKES_NULL
520 return getcwd(NULL
, 0);
521 #elif defined(HAVE_GETCWD)
522 char *wd
= NULL
, *s
= NULL
;
523 size_t allocated
= PATH_MAX
;
526 s
= SMB_REALLOC_ARRAY(s
, char, allocated
);
530 wd
= getcwd(s
, allocated
);
534 if (errno
!= ERANGE
) {
535 int saved_errno
= errno
;
541 if (allocated
< PATH_MAX
) {
549 char *s
= SMB_MALLOC_ARRAY(char, PATH_MAX
);
555 int saved_errno
= errno
;
563 #if defined(HAVE_POSIX_CAPABILITIES)
565 /**************************************************************************
566 Try and abstract process capabilities (for systems that have them).
567 ****************************************************************************/
569 /* Set the POSIX capabilities needed for the given purpose into the effective
570 * capability set of the current process. Make sure they are always removed
571 * from the inheritable set, because there is no circumstance in which our
572 * children should inherit our elevated privileges.
574 static bool set_process_capability(enum smbd_capability capability
,
577 /* "5" is the number of "num_cap_vals++" below */
578 cap_value_t cap_vals
[5] = {0};
579 size_t num_cap_vals
= 0;
583 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
584 /* On Linux, make sure that any capabilities we grab are sticky
585 * across UID changes. We expect that this would allow us to keep both
586 * the effective and permitted capability sets, but as of circa 2.6.16,
587 * only the permitted set is kept. It is a bug (which we work around)
588 * that the effective set is lost, but we still require the effective
591 if (!prctl(PR_GET_KEEPCAPS
)) {
592 prctl(PR_SET_KEEPCAPS
, 1);
596 cap
= cap_get_proc();
598 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
603 switch (capability
) {
605 * WARNING: If you add any #ifdef for a fresh
606 * capability, bump up the array size in the
607 * declaration of cap_vals[] above just to be
608 * trivially safe to never overwrite cap_vals[].
610 case KERNEL_OPLOCK_CAPABILITY
:
611 #ifdef CAP_NETWORK_MGT
612 /* IRIX has CAP_NETWORK_MGT for oplocks. */
613 cap_vals
[num_cap_vals
++] = CAP_NETWORK_MGT
;
616 case DMAPI_ACCESS_CAPABILITY
:
617 #ifdef CAP_DEVICE_MGT
618 /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
619 cap_vals
[num_cap_vals
++] = CAP_DEVICE_MGT
;
621 /* Linux has CAP_MKNOD for DMAPI access. */
622 cap_vals
[num_cap_vals
++] = CAP_MKNOD
;
625 case LEASE_CAPABILITY
:
627 cap_vals
[num_cap_vals
++] = CAP_LEASE
;
630 case DAC_OVERRIDE_CAPABILITY
:
631 #ifdef CAP_DAC_OVERRIDE
632 cap_vals
[num_cap_vals
++] = CAP_DAC_OVERRIDE
;
636 if (num_cap_vals
== 0) {
641 cap_set_flag(cap
, CAP_EFFECTIVE
, num_cap_vals
, cap_vals
,
642 enable
? CAP_SET
: CAP_CLEAR
);
644 /* We never want to pass capabilities down to our children, so make
645 * sure they are not inherited.
647 cap_set_flag(cap
, CAP_INHERITABLE
, num_cap_vals
, cap_vals
, CAP_CLEAR
);
649 if (cap_set_proc(cap
) == -1) {
650 DBG_ERR("%s capability %d: cap_set_proc failed: %s\n",
651 enable
? "adding" : "dropping",
652 capability
, strerror(errno
));
656 DBG_INFO("%s capability %d\n",
657 enable
? "added" : "dropped", capability
);
663 #endif /* HAVE_POSIX_CAPABILITIES */
665 /****************************************************************************
666 Gain the oplock capability from the kernel if possible.
667 ****************************************************************************/
669 #if defined(HAVE_POSIX_CAPABILITIES) && defined(CAP_DAC_OVERRIDE)
670 static bool have_cap_dac_override
= true;
672 static bool have_cap_dac_override
= false;
675 void set_effective_capability(enum smbd_capability capability
)
679 if (capability
!= DAC_OVERRIDE_CAPABILITY
|| have_cap_dac_override
) {
680 #if defined(HAVE_POSIX_CAPABILITIES)
681 ret
= set_process_capability(capability
, True
);
682 #endif /* HAVE_POSIX_CAPABILITIES */
686 * Fallback to become_root() if CAP_DAC_OVERRIDE is not
689 if (capability
== DAC_OVERRIDE_CAPABILITY
) {
691 have_cap_dac_override
= false;
693 if (!have_cap_dac_override
) {
699 void drop_effective_capability(enum smbd_capability capability
)
701 if (capability
!= DAC_OVERRIDE_CAPABILITY
|| have_cap_dac_override
) {
702 #if defined(HAVE_POSIX_CAPABILITIES)
703 set_process_capability(capability
, False
);
704 #endif /* HAVE_POSIX_CAPABILITIES */
710 /**************************************************************************
711 Wrapper for random().
712 ****************************************************************************/
714 long sys_random(void)
716 #if defined(HAVE_RANDOM)
717 return (long)random();
718 #elif defined(HAVE_RAND)
721 DEBUG(0,("Error - no random function available !\n"));
726 /**************************************************************************
727 Wrapper for srandom().
728 ****************************************************************************/
730 void sys_srandom(unsigned int seed
)
732 #if defined(HAVE_SRANDOM)
734 #elif defined(HAVE_SRAND)
737 DEBUG(0,("Error - no srandom function available !\n"));
743 #define NGROUPS_MAX 32 /* Guess... */
746 /**************************************************************************
747 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
748 ****************************************************************************/
750 int setgroups_max(void)
752 #if defined(SYSCONF_SC_NGROUPS_MAX)
753 int ret
= sysconf(_SC_NGROUPS_MAX
);
754 return (ret
== -1) ? NGROUPS_MAX
: ret
;
760 int getgroups_max(void)
762 #if defined(DARWINOS)
764 * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group
765 * nesting. However, The initgroups() manpage states the following:
766 * "Note that OS X supports group membership in an unlimited number
767 * of groups. The OS X kernel uses the group list stored in the process
768 * credentials only as an initial cache. Additional group memberships
769 * are determined by communication between the operating system and the
770 * opendirectoryd daemon."
774 return setgroups_max();
778 /**************************************************************************
779 Wrap setgroups and getgroups for systems that declare getgroups() as
780 returning an array of gid_t, but actually return an array of int.
781 ****************************************************************************/
783 #if defined(HAVE_BROKEN_GETGROUPS)
785 #ifdef HAVE_BROKEN_GETGROUPS
791 static int sys_broken_getgroups(int setlen
, gid_t
*gidset
)
797 return getgroups(0, NULL
);
801 * Broken case. We need to allocate a
802 * GID_T array of size setlen.
810 if((group_list
= SMB_MALLOC_ARRAY(GID_T
, setlen
)) == NULL
) {
811 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
815 if((ngroups
= getgroups(setlen
, group_list
)) < 0) {
816 int saved_errno
= errno
;
817 SAFE_FREE(group_list
);
823 * We're safe here as if ngroups > setlen then
824 * getgroups *must* return EINVAL.
825 * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
828 for(i
= 0; i
< ngroups
; i
++)
829 gidset
[i
] = (gid_t
)group_list
[i
];
831 SAFE_FREE(group_list
);
835 static int sys_broken_setgroups(int setlen
, gid_t
*gidset
)
843 if (setlen
< 0 || setlen
> setgroups_max()) {
849 * Broken case. We need to allocate a
850 * GID_T array of size setlen.
853 if((group_list
= SMB_MALLOC_ARRAY(GID_T
, setlen
)) == NULL
) {
854 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
858 for(i
= 0; i
< setlen
; i
++)
859 group_list
[i
] = (GID_T
) gidset
[i
];
861 if(samba_setgroups(setlen
, group_list
) != 0) {
862 int saved_errno
= errno
;
863 SAFE_FREE(group_list
);
868 SAFE_FREE(group_list
);
872 #endif /* HAVE_BROKEN_GETGROUPS */
874 /* This is a list of systems that require the first GID passed to setgroups(2)
875 * to be the effective GID. If your system is one of these, add it here.
877 #if defined (FREEBSD) || defined (DARWINOS)
878 #define USE_BSD_SETGROUPS
881 #if defined(USE_BSD_SETGROUPS)
882 /* Depending on the particular BSD implementation, the first GID that is
883 * passed to setgroups(2) will either be ignored or will set the credential's
884 * effective GID. In either case, the right thing to do is to guarantee that
885 * gidset[0] is the effective GID.
887 static int sys_bsd_setgroups(gid_t primary_gid
, int setlen
, const gid_t
*gidset
)
889 gid_t
*new_gidset
= NULL
;
893 /* setgroups(2) will fail with EINVAL if we pass too many groups. */
894 max
= setgroups_max();
896 /* No group list, just make sure we are setting the effective GID. */
898 return samba_setgroups(1, &primary_gid
);
901 /* If the primary gid is not the first array element, grow the array
902 * and insert it at the front.
904 if (gidset
[0] != primary_gid
) {
905 new_gidset
= SMB_MALLOC_ARRAY(gid_t
, setlen
+ 1);
906 if (new_gidset
== NULL
) {
910 memcpy(new_gidset
+ 1, gidset
, (setlen
* sizeof(gid_t
)));
911 new_gidset
[0] = primary_gid
;
916 DEBUG(3, ("forced to truncate group list from %d to %d\n",
921 #if defined(HAVE_BROKEN_GETGROUPS)
922 ret
= sys_broken_setgroups(setlen
, new_gidset
? new_gidset
: gidset
);
924 ret
= samba_setgroups(setlen
, new_gidset
? new_gidset
: gidset
);
929 SAFE_FREE(new_gidset
);
936 #endif /* USE_BSD_SETGROUPS */
938 /**************************************************************************
939 Wrapper for getgroups. Deals with broken (int) case.
940 ****************************************************************************/
942 int sys_getgroups(int setlen
, gid_t
*gidset
)
944 #if defined(HAVE_BROKEN_GETGROUPS)
945 return sys_broken_getgroups(setlen
, gidset
);
947 return getgroups(setlen
, gidset
);
951 /**************************************************************************
952 Wrapper for setgroups. Deals with broken (int) case and BSD case.
953 ****************************************************************************/
955 int sys_setgroups(gid_t
UNUSED(primary_gid
), int setlen
, gid_t
*gidset
)
957 #if !defined(HAVE_SETGROUPS)
960 #endif /* HAVE_SETGROUPS */
962 #if defined(USE_BSD_SETGROUPS)
963 return sys_bsd_setgroups(primary_gid
, setlen
, gidset
);
964 #elif defined(HAVE_BROKEN_GETGROUPS)
965 return sys_broken_setgroups(setlen
, gidset
);
967 return samba_setgroups(setlen
, gidset
);
971 /****************************************************************************
972 Return the major devicenumber for UNIX extensions.
973 ****************************************************************************/
975 uint32_t unix_dev_major(SMB_DEV_T dev
)
977 #if defined(HAVE_DEVICE_MAJOR_FN)
978 return (uint32_t)major(dev
);
980 return (uint32_t)(dev
>> 8);
984 /****************************************************************************
985 Return the minor devicenumber for UNIX extensions.
986 ****************************************************************************/
988 uint32_t unix_dev_minor(SMB_DEV_T dev
)
990 #if defined(HAVE_DEVICE_MINOR_FN)
991 return (uint32_t)minor(dev
);
993 return (uint32_t)(dev
& 0xff);
997 /**************************************************************************
998 Wrapper for realpath.
999 ****************************************************************************/
1001 char *sys_realpath(const char *path
)
1005 #ifdef REALPATH_TAKES_NULL
1006 result
= realpath(path
, NULL
);
1008 result
= SMB_MALLOC_ARRAY(char, PATH_MAX
+ 1);
1010 char *resolved_path
= realpath(path
, result
);
1011 if (!resolved_path
) {
1014 /* SMB_ASSERT(result == resolved_path) ? */
1015 result
= resolved_path
;
1023 /*******************************************************************
1024 Return the number of CPUs.
1025 ********************************************************************/
1027 int sys_get_number_of_cores(void)
1031 #if defined(HAVE_SYSCONF)
1032 #if defined(_SC_NPROCESSORS_ONLN)
1033 ret
= (int)sysconf(_SC_NPROCESSORS_ONLN
);
1035 #if defined(_SC_NPROCESSORS_CONF)
1037 ret
= (int)sysconf(_SC_NPROCESSORS_CONF
);
1040 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
1042 unsigned int len
= sizeof(ret
);
1045 #if defined(HW_AVAILCPU)
1046 name
[1] = HW_AVAILCPU
;
1048 if (sysctl(name
, 2, &ret
, &len
, NULL
, 0) == -1) {
1052 #if defined(HW_NCPU)
1056 if (sysctl(nm
, 2, &count
, &len
, NULL
, 0) == -1) {
1069 bool sys_have_proc_fds(void)
1071 static bool checked
= false;
1072 static bool have_proc_fds
= false;
1077 return have_proc_fds
;
1080 ret
= stat("/proc/self/fd/0", &sb
);
1081 have_proc_fds
= (ret
== 0);
1084 return have_proc_fds
;
1087 char *sys_proc_fd_path(int fd
, struct sys_proc_fd_path_buf
*buf
)
1090 snprintf(buf
->buf
, sizeof(buf
->buf
), "/proc/self/fd/%d", fd
);
1092 SMB_ASSERT(sys_have_proc_fds() && (written
>= 0));