s3:libads: make use of talloc_stackframe() in ads_setup_tls_wrapping()
[Samba.git] / source3 / lib / system.c
blob2006edbed6575b38652825048e30c1436bf0154c
1 /*
2 Unix SMB/CIFS implementation.
3 Samba system utilities
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/>.
23 #include "includes.h"
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>
33 #endif
35 #ifdef HAVE_SYS_PRCTL_H
36 #include <sys/prctl.h>
37 #endif
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)
60 ssize_t ret;
62 do {
63 ret = send(s, msg, len, flags);
64 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
66 return ret;
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)
76 ssize_t ret;
78 do {
79 ret = recvfrom(s, buf, len, flags, from, fromlen);
80 } while (ret == -1 && (errno == EINTR));
81 return ret;
84 /*******************************************************************
85 A fcntl wrapper that will deal with EINTR.
86 ********************************************************************/
88 int sys_fcntl_ptr(int fd, int cmd, void *arg)
90 int ret;
92 do {
93 ret = fcntl(fd, cmd, arg);
94 } while (ret == -1 && errno == EINTR);
95 return ret;
98 /*******************************************************************
99 A fcntl wrapper that will deal with EINTR.
100 ********************************************************************/
102 int sys_fcntl_long(int fd, int cmd, long arg)
104 int ret;
106 do {
107 ret = fcntl(fd, cmd, arg);
108 } while (ret == -1 && errno == EINTR);
109 return ret;
112 /*******************************************************************
113 A fcntl wrapper that will deal with EINTR.
114 ********************************************************************/
116 int sys_fcntl_int(int fd, int cmd, int arg)
118 int ret;
120 do {
121 ret = fcntl(fd, cmd, arg);
122 } while (ret == -1 && errno == EINTR);
123 return ret;
126 /****************************************************************************
127 Return the best approximation to a 'create time' under UNIX from a stat
128 structure.
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)) {
142 return ret1;
146 * One of ctime, mtime or atime was zero (probably atime).
147 * Just return MIN(ctime, mtime).
149 return ret;
152 /****************************************************************************
153 Return the best approximation to a 'create time' under UNIX from a stat_ex
154 structure.
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)) {
168 return ret1;
172 * One of ctime, mtime or atime was zero (probably atime).
173 * Just return MIN(ctime, mtime).
175 return ret;
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;
189 return;
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;
202 #else
203 dst->st_ex_btime = calc_create_time_stat(pst);
204 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
205 #endif
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)) {
244 return;
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;
290 #else
291 dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
292 #endif
294 #ifdef HAVE_STAT_ST_BLOCKS
295 dst->st_ex_blocks = src->st_blocks;
296 #else
297 dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
298 #endif
300 #ifdef HAVE_STAT_ST_FLAGS
301 dst->st_ex_flags = src->st_flags;
302 #else
303 dst->st_ex_flags = 0;
304 #endif
307 /*******************************************************************
308 A stat() wrapper.
309 ********************************************************************/
311 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
312 bool fake_dir_create_times)
314 int ret;
315 struct stat statbuf;
316 ret = stat(fname, &statbuf);
317 if (ret == 0) {
318 /* we always want directories to appear zero size */
319 if (S_ISDIR(statbuf.st_mode)) {
320 statbuf.st_size = 0;
322 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
324 return ret;
327 /*******************************************************************
328 An fstat() wrapper.
329 ********************************************************************/
331 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
333 int ret;
334 struct stat statbuf;
335 ret = fstat(fd, &statbuf);
336 if (ret == 0) {
337 /* we always want directories to appear zero size */
338 if (S_ISDIR(statbuf.st_mode)) {
339 statbuf.st_size = 0;
341 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
343 return ret;
346 /*******************************************************************
347 An lstat() wrapper.
348 ********************************************************************/
350 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
351 bool fake_dir_create_times)
353 int ret;
354 struct stat statbuf;
355 ret = lstat(fname, &statbuf);
356 if (ret == 0) {
357 /* we always want directories to appear zero size */
358 if (S_ISDIR(statbuf.st_mode)) {
359 statbuf.st_size = 0;
361 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
363 return ret;
366 /*******************************************************************
367 An fstatat() wrapper.
368 ********************************************************************/
370 int sys_fstatat(int fd,
371 const char *pathname,
372 SMB_STRUCT_STAT *sbuf,
373 int flags,
374 bool fake_dir_create_times)
376 int ret;
377 struct stat statbuf;
379 ret = fstatat(fd, pathname, &statbuf, flags);
380 if (ret != 0) {
381 return -1;
384 /* we always want directories to appear zero size */
385 if (S_ISDIR(statbuf.st_mode)) {
386 statbuf.st_size = 0;
388 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
389 return 0;
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 */
401 struct flock64 fl;
402 off_t new_len = offset + len;
403 int ret;
404 struct stat64 sbuf;
406 /* unlikely to get a too large file on a 64bit system but ... */
407 if (new_len < 0)
408 return EFBIG;
410 fl.l_whence = SEEK_SET;
411 fl.l_start = offset;
412 fl.l_len = len;
414 ret=fcntl(fd, F_RESVSP64, &fl);
416 if (ret != 0)
417 return errno;
419 /* Make sure the file gets enlarged after we allocated space: */
420 fstat64(fd, &sbuf);
421 if (new_len > sbuf.st_size)
422 ftruncate64(fd, new_len);
423 return 0;
424 #else
425 return ENOSYS;
426 #endif
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>
435 #endif
437 int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len)
439 #if defined(HAVE_LINUX_FALLOCATE)
440 int lmode = 0;
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 */
454 if (mode != 0) {
455 DEBUG(2, ("unmapped fallocate flags: %lx\n",
456 (unsigned long)mode));
457 errno = EINVAL;
458 return -1;
460 return fallocate(fd, lmode, offset, len);
461 #else /* HAVE_LINUX_FALLOCATE */
462 /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
463 errno = ENOSYS;
464 return -1;
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);
476 #else
477 errno = ENOSYS;
478 return NULL;
479 #endif
482 /*******************************************************************
483 An mknod() wrapper.
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);
490 #else
491 /* No mknod system call. */
492 errno = ENOSYS;
493 return -1;
494 #endif
497 /*******************************************************************
498 A mknodat() wrapper.
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);
505 #else
506 /* No mknod system call. */
507 errno = ENOSYS;
508 return -1;
509 #endif
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;
525 while (1) {
526 s = SMB_REALLOC_ARRAY(s, char, allocated);
527 if (s == NULL) {
528 return NULL;
530 wd = getcwd(s, allocated);
531 if (wd) {
532 break;
534 if (errno != ERANGE) {
535 int saved_errno = errno;
536 SAFE_FREE(s);
537 errno = saved_errno;
538 break;
540 allocated *= 2;
541 if (allocated < PATH_MAX) {
542 SAFE_FREE(s);
543 break;
546 return wd;
547 #else
548 char *wd = NULL;
549 char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
550 if (s == NULL) {
551 return NULL;
553 wd = getwd(s);
554 if (wd == NULL) {
555 int saved_errno = errno;
556 SAFE_FREE(s);
557 errno = saved_errno;
559 return wd;
560 #endif
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,
575 bool enable)
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;
581 cap_t cap;
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
589 * set to be kept.
591 if (!prctl(PR_GET_KEEPCAPS)) {
592 prctl(PR_SET_KEEPCAPS, 1);
594 #endif
596 cap = cap_get_proc();
597 if (cap == NULL) {
598 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
599 strerror(errno)));
600 return False;
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;
614 #endif
615 break;
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;
620 #elif CAP_MKNOD
621 /* Linux has CAP_MKNOD for DMAPI access. */
622 cap_vals[num_cap_vals++] = CAP_MKNOD;
623 #endif
624 break;
625 case LEASE_CAPABILITY:
626 #ifdef CAP_LEASE
627 cap_vals[num_cap_vals++] = CAP_LEASE;
628 #endif
629 break;
630 case DAC_OVERRIDE_CAPABILITY:
631 #ifdef CAP_DAC_OVERRIDE
632 cap_vals[num_cap_vals++] = CAP_DAC_OVERRIDE;
633 #endif
636 if (num_cap_vals == 0) {
637 cap_free(cap);
638 return True;
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));
653 cap_free(cap);
654 return False;
656 DBG_INFO("%s capability %d\n",
657 enable ? "added" : "dropped", capability);
659 cap_free(cap);
660 return True;
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;
671 #else
672 static bool have_cap_dac_override = false;
673 #endif
675 void set_effective_capability(enum smbd_capability capability)
677 bool ret = false;
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
687 * available.
689 if (capability == DAC_OVERRIDE_CAPABILITY) {
690 if (!ret) {
691 have_cap_dac_override = false;
693 if (!have_cap_dac_override) {
694 become_root();
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 */
705 } else {
706 unbecome_root();
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)
719 return (long)rand();
720 #else
721 DEBUG(0,("Error - no random function available !\n"));
722 exit(1);
723 #endif
726 /**************************************************************************
727 Wrapper for srandom().
728 ****************************************************************************/
730 void sys_srandom(unsigned int seed)
732 #if defined(HAVE_SRANDOM)
733 srandom(seed);
734 #elif defined(HAVE_SRAND)
735 srand(seed);
736 #else
737 DEBUG(0,("Error - no srandom function available !\n"));
738 exit(1);
739 #endif
742 #ifndef NGROUPS_MAX
743 #define NGROUPS_MAX 32 /* Guess... */
744 #endif
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;
755 #else
756 return NGROUPS_MAX;
757 #endif
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."
772 return INT_MAX;
773 #else
774 return setgroups_max();
775 #endif
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
786 #define GID_T int
787 #else
788 #define GID_T gid_t
789 #endif
791 static int sys_broken_getgroups(int setlen, gid_t *gidset)
793 GID_T *group_list;
794 int i, ngroups;
796 if(setlen == 0) {
797 return getgroups(0, NULL);
801 * Broken case. We need to allocate a
802 * GID_T array of size setlen.
805 if(setlen < 0) {
806 errno = EINVAL;
807 return -1;
810 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
811 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
812 return -1;
815 if((ngroups = getgroups(setlen, group_list)) < 0) {
816 int saved_errno = errno;
817 SAFE_FREE(group_list);
818 errno = saved_errno;
819 return -1;
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);
832 return ngroups;
835 static int sys_broken_setgroups(int setlen, gid_t *gidset)
837 GID_T *group_list;
838 int i ;
840 if (setlen == 0)
841 return 0 ;
843 if (setlen < 0 || setlen > setgroups_max()) {
844 errno = EINVAL;
845 return -1;
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"));
855 return -1;
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);
864 errno = saved_errno;
865 return -1;
868 SAFE_FREE(group_list);
869 return 0 ;
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
879 #endif
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;
890 int max;
891 int ret;
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. */
897 if (setlen == 0) {
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) {
907 return -1;
910 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
911 new_gidset[0] = primary_gid;
912 setlen++;
915 if (setlen > max) {
916 DEBUG(3, ("forced to truncate group list from %d to %d\n",
917 setlen, max));
918 setlen = max;
921 #if defined(HAVE_BROKEN_GETGROUPS)
922 ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
923 #else
924 ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
925 #endif
927 if (new_gidset) {
928 int errsav = errno;
929 SAFE_FREE(new_gidset);
930 errno = errsav;
933 return ret;
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);
946 #else
947 return getgroups(setlen, gidset);
948 #endif
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)
958 errno = ENOSYS;
959 return -1;
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);
966 #else
967 return samba_setgroups(setlen, gidset);
968 #endif
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);
979 #else
980 return (uint32_t)(dev >> 8);
981 #endif
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);
992 #else
993 return (uint32_t)(dev & 0xff);
994 #endif
997 /**************************************************************************
998 Wrapper for realpath.
999 ****************************************************************************/
1001 char *sys_realpath(const char *path)
1003 char *result;
1005 #ifdef REALPATH_TAKES_NULL
1006 result = realpath(path, NULL);
1007 #else
1008 result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
1009 if (result) {
1010 char *resolved_path = realpath(path, result);
1011 if (!resolved_path) {
1012 SAFE_FREE(result);
1013 } else {
1014 /* SMB_ASSERT(result == resolved_path) ? */
1015 result = resolved_path;
1018 #endif
1019 return result;
1022 #if 0
1023 /*******************************************************************
1024 Return the number of CPUs.
1025 ********************************************************************/
1027 int sys_get_number_of_cores(void)
1029 int ret = -1;
1031 #if defined(HAVE_SYSCONF)
1032 #if defined(_SC_NPROCESSORS_ONLN)
1033 ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
1034 #endif
1035 #if defined(_SC_NPROCESSORS_CONF)
1036 if (ret < 1) {
1037 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
1039 #endif
1040 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
1041 int name[2];
1042 unsigned int len = sizeof(ret);
1044 name[0] = CTL_HW;
1045 #if defined(HW_AVAILCPU)
1046 name[1] = HW_AVAILCPU;
1048 if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
1049 ret = -1;
1051 #endif
1052 #if defined(HW_NCPU)
1053 if(ret < 1) {
1054 name[0] = CTL_HW;
1055 name[1] = HW_NCPU;
1056 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
1057 ret = -1;
1060 #endif
1061 #endif
1062 if (ret < 1) {
1063 ret = 1;
1065 return ret;
1067 #endif
1069 bool sys_have_proc_fds(void)
1071 static bool checked = false;
1072 static bool have_proc_fds = false;
1073 struct stat sb;
1074 int ret;
1076 if (checked) {
1077 return have_proc_fds;
1080 ret = stat("/proc/self/fd/0", &sb);
1081 have_proc_fds = (ret == 0);
1082 checked = true;
1084 return have_proc_fds;
1087 char *sys_proc_fd_path(int fd, struct sys_proc_fd_path_buf *buf)
1089 int written =
1090 snprintf(buf->buf, sizeof(buf->buf), "/proc/self/fd/%d", fd);
1092 SMB_ASSERT(sys_have_proc_fds() && (written >= 0));
1094 return buf->buf;