auth4: Fix CID 1034877 Resource leak
[Samba.git] / source3 / lib / system.c
blobe882e173f117ae3d63836ad7f1bf83016d0a5fcb
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(struct stat_ex *st,
253 const struct smb_file_time *ft)
255 if (!is_omit_timespec(&ft->atime)) {
256 st->st_ex_atime = ft->atime;
259 if (!is_omit_timespec(&ft->create_time)) {
260 st->st_ex_btime = ft->create_time;
263 if (!is_omit_timespec(&ft->ctime)) {
264 st->st_ex_ctime = ft->ctime;
267 if (!is_omit_timespec(&ft->mtime)) {
268 st->st_ex_mtime = ft->mtime;
272 void init_stat_ex_from_stat (struct stat_ex *dst,
273 const struct stat *src,
274 bool fake_dir_create_times)
276 dst->st_ex_dev = src->st_dev;
277 dst->st_ex_ino = src->st_ino;
278 dst->st_ex_mode = src->st_mode;
279 dst->st_ex_nlink = src->st_nlink;
280 dst->st_ex_uid = src->st_uid;
281 dst->st_ex_gid = src->st_gid;
282 dst->st_ex_rdev = src->st_rdev;
283 dst->st_ex_size = src->st_size;
284 dst->st_ex_atime = get_atimespec(src);
285 dst->st_ex_mtime = get_mtimespec(src);
286 dst->st_ex_ctime = get_ctimespec(src);
287 dst->st_ex_iflags = 0;
288 make_create_timespec(src, dst, fake_dir_create_times);
289 #ifdef HAVE_STAT_ST_BLKSIZE
290 dst->st_ex_blksize = src->st_blksize;
291 #else
292 dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
293 #endif
295 #ifdef HAVE_STAT_ST_BLOCKS
296 dst->st_ex_blocks = src->st_blocks;
297 #else
298 dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
299 #endif
301 #ifdef HAVE_STAT_ST_FLAGS
302 dst->st_ex_flags = src->st_flags;
303 #else
304 dst->st_ex_flags = 0;
305 #endif
308 /*******************************************************************
309 A stat() wrapper.
310 ********************************************************************/
312 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
313 bool fake_dir_create_times)
315 int ret;
316 struct stat statbuf;
317 ret = stat(fname, &statbuf);
318 if (ret == 0) {
319 /* we always want directories to appear zero size */
320 if (S_ISDIR(statbuf.st_mode)) {
321 statbuf.st_size = 0;
323 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
325 return ret;
328 /*******************************************************************
329 An fstat() wrapper.
330 ********************************************************************/
332 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
334 int ret;
335 struct stat statbuf;
336 ret = fstat(fd, &statbuf);
337 if (ret == 0) {
338 /* we always want directories to appear zero size */
339 if (S_ISDIR(statbuf.st_mode)) {
340 statbuf.st_size = 0;
342 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
344 return ret;
347 /*******************************************************************
348 An lstat() wrapper.
349 ********************************************************************/
351 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
352 bool fake_dir_create_times)
354 int ret;
355 struct stat statbuf;
356 ret = lstat(fname, &statbuf);
357 if (ret == 0) {
358 /* we always want directories to appear zero size */
359 if (S_ISDIR(statbuf.st_mode)) {
360 statbuf.st_size = 0;
362 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
364 return ret;
367 /*******************************************************************
368 An fstatat() wrapper.
369 ********************************************************************/
371 int sys_fstatat(int fd,
372 const char *pathname,
373 SMB_STRUCT_STAT *sbuf,
374 int flags,
375 bool fake_dir_create_times)
377 int ret;
378 struct stat statbuf;
380 ret = fstatat(fd, pathname, &statbuf, flags);
381 if (ret != 0) {
382 return -1;
385 /* we always want directories to appear zero size */
386 if (S_ISDIR(statbuf.st_mode)) {
387 statbuf.st_size = 0;
389 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
390 return 0;
393 /*******************************************************************
394 An posix_fallocate() wrapper.
395 ********************************************************************/
396 int sys_posix_fallocate(int fd, off_t offset, off_t len)
398 #if defined(HAVE_POSIX_FALLOCATE)
399 return posix_fallocate(fd, offset, len);
400 #elif defined(F_RESVSP64)
401 /* this handles XFS on IRIX */
402 struct flock64 fl;
403 off_t new_len = offset + len;
404 int ret;
405 struct stat64 sbuf;
407 /* unlikely to get a too large file on a 64bit system but ... */
408 if (new_len < 0)
409 return EFBIG;
411 fl.l_whence = SEEK_SET;
412 fl.l_start = offset;
413 fl.l_len = len;
415 ret=fcntl(fd, F_RESVSP64, &fl);
417 if (ret != 0)
418 return errno;
420 /* Make sure the file gets enlarged after we allocated space: */
421 fstat64(fd, &sbuf);
422 if (new_len > sbuf.st_size)
423 ftruncate64(fd, new_len);
424 return 0;
425 #else
426 return ENOSYS;
427 #endif
430 /*******************************************************************
431 An fallocate() function that matches the semantics of the Linux one.
432 ********************************************************************/
434 #ifdef HAVE_LINUX_FALLOC_H
435 #include <linux/falloc.h>
436 #endif
438 int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len)
440 #if defined(HAVE_LINUX_FALLOCATE)
441 int lmode = 0;
443 if (mode & VFS_FALLOCATE_FL_KEEP_SIZE) {
444 lmode |= FALLOC_FL_KEEP_SIZE;
445 mode &= ~VFS_FALLOCATE_FL_KEEP_SIZE;
448 #if defined(HAVE_FALLOC_FL_PUNCH_HOLE)
449 if (mode & VFS_FALLOCATE_FL_PUNCH_HOLE) {
450 lmode |= FALLOC_FL_PUNCH_HOLE;
451 mode &= ~VFS_FALLOCATE_FL_PUNCH_HOLE;
453 #endif /* HAVE_FALLOC_FL_PUNCH_HOLE */
455 if (mode != 0) {
456 DEBUG(2, ("unmapped fallocate flags: %lx\n",
457 (unsigned long)mode));
458 errno = EINVAL;
459 return -1;
461 return fallocate(fd, lmode, offset, len);
462 #else /* HAVE_LINUX_FALLOCATE */
463 /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
464 errno = ENOSYS;
465 return -1;
466 #endif /* HAVE_LINUX_FALLOCATE */
469 /*******************************************************************
470 An fdopendir wrapper.
471 ********************************************************************/
473 DIR *sys_fdopendir(int fd)
475 #if defined(HAVE_FDOPENDIR)
476 return fdopendir(fd);
477 #else
478 errno = ENOSYS;
479 return NULL;
480 #endif
483 /*******************************************************************
484 An mknod() wrapper.
485 ********************************************************************/
487 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
489 #if defined(HAVE_MKNOD)
490 return mknod(path, mode, dev);
491 #else
492 /* No mknod system call. */
493 errno = ENOSYS;
494 return -1;
495 #endif
498 /*******************************************************************
499 A mknodat() wrapper.
500 ********************************************************************/
502 int sys_mknodat(int dirfd, const char *path, mode_t mode, SMB_DEV_T dev)
504 #if defined(HAVE_MKNODAT)
505 return mknodat(dirfd, path, mode, dev);
506 #else
507 /* No mknod system call. */
508 errno = ENOSYS;
509 return -1;
510 #endif
513 /*******************************************************************
514 System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
515 on error (malloc fail usually).
516 ********************************************************************/
518 char *sys_getwd(void)
520 #ifdef GETCWD_TAKES_NULL
521 return getcwd(NULL, 0);
522 #elif defined(HAVE_GETCWD)
523 char *wd = NULL, *s = NULL;
524 size_t allocated = PATH_MAX;
526 while (1) {
527 s = SMB_REALLOC_ARRAY(s, char, allocated);
528 if (s == NULL) {
529 return NULL;
531 wd = getcwd(s, allocated);
532 if (wd) {
533 break;
535 if (errno != ERANGE) {
536 int saved_errno = errno;
537 SAFE_FREE(s);
538 errno = saved_errno;
539 break;
541 allocated *= 2;
542 if (allocated < PATH_MAX) {
543 SAFE_FREE(s);
544 break;
547 return wd;
548 #else
549 char *wd = NULL;
550 char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
551 if (s == NULL) {
552 return NULL;
554 wd = getwd(s);
555 if (wd == NULL) {
556 int saved_errno = errno;
557 SAFE_FREE(s);
558 errno = saved_errno;
560 return wd;
561 #endif
564 #if defined(HAVE_POSIX_CAPABILITIES)
566 /**************************************************************************
567 Try and abstract process capabilities (for systems that have them).
568 ****************************************************************************/
570 /* Set the POSIX capabilities needed for the given purpose into the effective
571 * capability set of the current process. Make sure they are always removed
572 * from the inheritable set, because there is no circumstance in which our
573 * children should inherit our elevated privileges.
575 static bool set_process_capability(enum smbd_capability capability,
576 bool enable)
578 /* "5" is the number of "num_cap_vals++" below */
579 cap_value_t cap_vals[5] = {0};
580 size_t num_cap_vals = 0;
582 cap_t cap;
584 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
585 /* On Linux, make sure that any capabilities we grab are sticky
586 * across UID changes. We expect that this would allow us to keep both
587 * the effective and permitted capability sets, but as of circa 2.6.16,
588 * only the permitted set is kept. It is a bug (which we work around)
589 * that the effective set is lost, but we still require the effective
590 * set to be kept.
592 if (!prctl(PR_GET_KEEPCAPS)) {
593 prctl(PR_SET_KEEPCAPS, 1);
595 #endif
597 cap = cap_get_proc();
598 if (cap == NULL) {
599 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
600 strerror(errno)));
601 return False;
604 switch (capability) {
606 * WARNING: If you add any #ifdef for a fresh
607 * capability, bump up the array size in the
608 * declaration of cap_vals[] above just to be
609 * trivially safe to never overwrite cap_vals[].
611 case KERNEL_OPLOCK_CAPABILITY:
612 #ifdef CAP_NETWORK_MGT
613 /* IRIX has CAP_NETWORK_MGT for oplocks. */
614 cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
615 #endif
616 break;
617 case DMAPI_ACCESS_CAPABILITY:
618 #ifdef CAP_DEVICE_MGT
619 /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
620 cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
621 #elif CAP_MKNOD
622 /* Linux has CAP_MKNOD for DMAPI access. */
623 cap_vals[num_cap_vals++] = CAP_MKNOD;
624 #endif
625 break;
626 case LEASE_CAPABILITY:
627 #ifdef CAP_LEASE
628 cap_vals[num_cap_vals++] = CAP_LEASE;
629 #endif
630 break;
631 case DAC_OVERRIDE_CAPABILITY:
632 #ifdef CAP_DAC_OVERRIDE
633 cap_vals[num_cap_vals++] = CAP_DAC_OVERRIDE;
634 #endif
637 if (num_cap_vals == 0) {
638 cap_free(cap);
639 return True;
642 cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
643 enable ? CAP_SET : CAP_CLEAR);
645 /* We never want to pass capabilities down to our children, so make
646 * sure they are not inherited.
648 cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
650 if (cap_set_proc(cap) == -1) {
651 DBG_ERR("%s capability %d: cap_set_proc failed: %s\n",
652 enable ? "adding" : "dropping",
653 capability, strerror(errno));
654 cap_free(cap);
655 return False;
657 DBG_INFO("%s capability %d\n",
658 enable ? "added" : "dropped", capability);
660 cap_free(cap);
661 return True;
664 #endif /* HAVE_POSIX_CAPABILITIES */
666 /****************************************************************************
667 Gain the oplock capability from the kernel if possible.
668 ****************************************************************************/
670 #if defined(HAVE_POSIX_CAPABILITIES) && defined(CAP_DAC_OVERRIDE)
671 static bool have_cap_dac_override = true;
672 #else
673 static bool have_cap_dac_override = false;
674 #endif
676 void set_effective_capability(enum smbd_capability capability)
678 bool ret = false;
680 if (capability != DAC_OVERRIDE_CAPABILITY || have_cap_dac_override) {
681 #if defined(HAVE_POSIX_CAPABILITIES)
682 ret = set_process_capability(capability, True);
683 #endif /* HAVE_POSIX_CAPABILITIES */
687 * Fallback to become_root() if CAP_DAC_OVERRIDE is not
688 * available.
690 if (capability == DAC_OVERRIDE_CAPABILITY) {
691 if (!ret) {
692 have_cap_dac_override = false;
694 if (!have_cap_dac_override) {
695 become_root();
700 void drop_effective_capability(enum smbd_capability capability)
702 if (capability != DAC_OVERRIDE_CAPABILITY || have_cap_dac_override) {
703 #if defined(HAVE_POSIX_CAPABILITIES)
704 set_process_capability(capability, False);
705 #endif /* HAVE_POSIX_CAPABILITIES */
706 } else {
707 unbecome_root();
711 /**************************************************************************
712 Wrapper for random().
713 ****************************************************************************/
715 long sys_random(void)
717 #if defined(HAVE_RANDOM)
718 return (long)random();
719 #elif defined(HAVE_RAND)
720 return (long)rand();
721 #else
722 DEBUG(0,("Error - no random function available !\n"));
723 exit(1);
724 #endif
727 /**************************************************************************
728 Wrapper for srandom().
729 ****************************************************************************/
731 void sys_srandom(unsigned int seed)
733 #if defined(HAVE_SRANDOM)
734 srandom(seed);
735 #elif defined(HAVE_SRAND)
736 srand(seed);
737 #else
738 DEBUG(0,("Error - no srandom function available !\n"));
739 exit(1);
740 #endif
743 #ifndef NGROUPS_MAX
744 #define NGROUPS_MAX 32 /* Guess... */
745 #endif
747 /**************************************************************************
748 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
749 ****************************************************************************/
751 int setgroups_max(void)
753 #if defined(SYSCONF_SC_NGROUPS_MAX)
754 int ret = sysconf(_SC_NGROUPS_MAX);
755 return (ret == -1) ? NGROUPS_MAX : ret;
756 #else
757 return NGROUPS_MAX;
758 #endif
761 int getgroups_max(void)
763 #if defined(DARWINOS)
765 * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group
766 * nesting. However, The initgroups() manpage states the following:
767 * "Note that OS X supports group membership in an unlimited number
768 * of groups. The OS X kernel uses the group list stored in the process
769 * credentials only as an initial cache. Additional group memberships
770 * are determined by communication between the operating system and the
771 * opendirectoryd daemon."
773 return INT_MAX;
774 #else
775 return setgroups_max();
776 #endif
779 /**************************************************************************
780 Wrap setgroups and getgroups for systems that declare getgroups() as
781 returning an array of gid_t, but actually return an array of int.
782 ****************************************************************************/
784 #if defined(HAVE_BROKEN_GETGROUPS)
786 #ifdef HAVE_BROKEN_GETGROUPS
787 #define GID_T int
788 #else
789 #define GID_T gid_t
790 #endif
792 static int sys_broken_getgroups(int setlen, gid_t *gidset)
794 GID_T *group_list;
795 int i, ngroups;
797 if(setlen == 0) {
798 return getgroups(0, NULL);
802 * Broken case. We need to allocate a
803 * GID_T array of size setlen.
806 if(setlen < 0) {
807 errno = EINVAL;
808 return -1;
811 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
812 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
813 return -1;
816 if((ngroups = getgroups(setlen, group_list)) < 0) {
817 int saved_errno = errno;
818 SAFE_FREE(group_list);
819 errno = saved_errno;
820 return -1;
824 * We're safe here as if ngroups > setlen then
825 * getgroups *must* return EINVAL.
826 * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
829 for(i = 0; i < ngroups; i++)
830 gidset[i] = (gid_t)group_list[i];
832 SAFE_FREE(group_list);
833 return ngroups;
836 static int sys_broken_setgroups(int setlen, gid_t *gidset)
838 GID_T *group_list;
839 int i ;
841 if (setlen == 0)
842 return 0 ;
844 if (setlen < 0 || setlen > setgroups_max()) {
845 errno = EINVAL;
846 return -1;
850 * Broken case. We need to allocate a
851 * GID_T array of size setlen.
854 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
855 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
856 return -1;
859 for(i = 0; i < setlen; i++)
860 group_list[i] = (GID_T) gidset[i];
862 if(samba_setgroups(setlen, group_list) != 0) {
863 int saved_errno = errno;
864 SAFE_FREE(group_list);
865 errno = saved_errno;
866 return -1;
869 SAFE_FREE(group_list);
870 return 0 ;
873 #endif /* HAVE_BROKEN_GETGROUPS */
875 /* This is a list of systems that require the first GID passed to setgroups(2)
876 * to be the effective GID. If your system is one of these, add it here.
878 #if defined (FREEBSD) || defined (DARWINOS)
879 #define USE_BSD_SETGROUPS
880 #endif
882 #if defined(USE_BSD_SETGROUPS)
883 /* Depending on the particular BSD implementation, the first GID that is
884 * passed to setgroups(2) will either be ignored or will set the credential's
885 * effective GID. In either case, the right thing to do is to guarantee that
886 * gidset[0] is the effective GID.
888 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
890 gid_t *new_gidset = NULL;
891 int max;
892 int ret;
894 /* setgroups(2) will fail with EINVAL if we pass too many groups. */
895 max = setgroups_max();
897 /* No group list, just make sure we are setting the effective GID. */
898 if (setlen == 0) {
899 return samba_setgroups(1, &primary_gid);
902 /* If the primary gid is not the first array element, grow the array
903 * and insert it at the front.
905 if (gidset[0] != primary_gid) {
906 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
907 if (new_gidset == NULL) {
908 return -1;
911 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
912 new_gidset[0] = primary_gid;
913 setlen++;
916 if (setlen > max) {
917 DEBUG(3, ("forced to truncate group list from %d to %d\n",
918 setlen, max));
919 setlen = max;
922 #if defined(HAVE_BROKEN_GETGROUPS)
923 ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
924 #else
925 ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
926 #endif
928 if (new_gidset) {
929 int errsav = errno;
930 SAFE_FREE(new_gidset);
931 errno = errsav;
934 return ret;
937 #endif /* USE_BSD_SETGROUPS */
939 /**************************************************************************
940 Wrapper for getgroups. Deals with broken (int) case.
941 ****************************************************************************/
943 int sys_getgroups(int setlen, gid_t *gidset)
945 #if defined(HAVE_BROKEN_GETGROUPS)
946 return sys_broken_getgroups(setlen, gidset);
947 #else
948 return getgroups(setlen, gidset);
949 #endif
952 /**************************************************************************
953 Wrapper for setgroups. Deals with broken (int) case and BSD case.
954 ****************************************************************************/
956 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
958 #if !defined(HAVE_SETGROUPS)
959 errno = ENOSYS;
960 return -1;
961 #endif /* HAVE_SETGROUPS */
963 #if defined(USE_BSD_SETGROUPS)
964 return sys_bsd_setgroups(primary_gid, setlen, gidset);
965 #elif defined(HAVE_BROKEN_GETGROUPS)
966 return sys_broken_setgroups(setlen, gidset);
967 #else
968 return samba_setgroups(setlen, gidset);
969 #endif
972 /****************************************************************************
973 Return the major devicenumber for UNIX extensions.
974 ****************************************************************************/
976 uint32_t unix_dev_major(SMB_DEV_T dev)
978 #if defined(HAVE_DEVICE_MAJOR_FN)
979 return (uint32_t)major(dev);
980 #else
981 return (uint32_t)(dev >> 8);
982 #endif
985 /****************************************************************************
986 Return the minor devicenumber for UNIX extensions.
987 ****************************************************************************/
989 uint32_t unix_dev_minor(SMB_DEV_T dev)
991 #if defined(HAVE_DEVICE_MINOR_FN)
992 return (uint32_t)minor(dev);
993 #else
994 return (uint32_t)(dev & 0xff);
995 #endif
998 /**************************************************************************
999 Wrapper for realpath.
1000 ****************************************************************************/
1002 char *sys_realpath(const char *path)
1004 char *result;
1006 #ifdef REALPATH_TAKES_NULL
1007 result = realpath(path, NULL);
1008 #else
1009 result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
1010 if (result) {
1011 char *resolved_path = realpath(path, result);
1012 if (!resolved_path) {
1013 SAFE_FREE(result);
1014 } else {
1015 /* SMB_ASSERT(result == resolved_path) ? */
1016 result = resolved_path;
1019 #endif
1020 return result;
1023 #if 0
1024 /*******************************************************************
1025 Return the number of CPUs.
1026 ********************************************************************/
1028 int sys_get_number_of_cores(void)
1030 int ret = -1;
1032 #if defined(HAVE_SYSCONF)
1033 #if defined(_SC_NPROCESSORS_ONLN)
1034 ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
1035 #endif
1036 #if defined(_SC_NPROCESSORS_CONF)
1037 if (ret < 1) {
1038 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
1040 #endif
1041 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
1042 int name[2];
1043 unsigned int len = sizeof(ret);
1045 name[0] = CTL_HW;
1046 #if defined(HW_AVAILCPU)
1047 name[1] = HW_AVAILCPU;
1049 if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
1050 ret = -1;
1052 #endif
1053 #if defined(HW_NCPU)
1054 if(ret < 1) {
1055 name[0] = CTL_HW;
1056 name[1] = HW_NCPU;
1057 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
1058 ret = -1;
1061 #endif
1062 #endif
1063 if (ret < 1) {
1064 ret = 1;
1066 return ret;
1068 #endif
1070 bool sys_have_proc_fds(void)
1072 static bool checked = false;
1073 static bool have_proc_fds = false;
1074 struct stat sb;
1075 int ret;
1077 if (checked) {
1078 return have_proc_fds;
1081 ret = stat("/proc/self/fd/0", &sb);
1082 have_proc_fds = (ret == 0);
1083 checked = true;
1085 return have_proc_fds;
1088 char *sys_proc_fd_path(int fd, struct sys_proc_fd_path_buf *buf)
1090 int written =
1091 snprintf(buf->buf, sizeof(buf->buf), "/proc/self/fd/%d", fd);
1093 SMB_ASSERT(sys_have_proc_fds() && (written >= 0));
1095 return buf->buf;