system.c: fix fake directory create times
[samba.git] / source3 / lib / system.c
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
8
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.
13
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.
18
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/>.
21 */
22
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"
30
31 #ifdef HAVE_SYS_SYSCTL_H
32 #include <sys/sysctl.h>
33 #endif
34
35 #ifdef HAVE_SYS_PRCTL_H
36 #include <sys/prctl.h>
37 #endif
38
39 /*
40    The idea is that this file will eventually have wrappers around all
41    important system calls in samba. The aims are:
42
43    - to enable easier porting by putting OS dependent stuff in here
44
45    - to allow for hooks into other "pseudo-filesystems"
46
47    - to allow easier integration of things like the japanese extensions
48
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.
52 */
53
54 /*******************************************************************
55 A send wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK.
56 ********************************************************************/
57
58 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
59 {
60         ssize_t ret;
61
62         do {
63                 ret = send(s, msg, len, flags);
64         } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
65
66         return ret;
67 }
68
69 /*******************************************************************
70 A recvfrom wrapper that will deal with EINTR.
71 NB. As used with non-blocking sockets, return on EAGAIN/EWOULDBLOCK
72 ********************************************************************/
73
74 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
75 {
76         ssize_t ret;
77
78         do {
79                 ret = recvfrom(s, buf, len, flags, from, fromlen);
80         } while (ret == -1 && (errno == EINTR));
81         return ret;
82 }
83
84 /*******************************************************************
85 A fcntl wrapper that will deal with EINTR.
86 ********************************************************************/
87
88 int sys_fcntl_ptr(int fd, int cmd, void *arg)
89 {
90         int ret;
91
92         do {
93                 ret = fcntl(fd, cmd, arg);
94         } while (ret == -1 && errno == EINTR);
95         return ret;
96 }
97
98 /*******************************************************************
99 A fcntl wrapper that will deal with EINTR.
100 ********************************************************************/
101
102 int sys_fcntl_long(int fd, int cmd, long arg)
103 {
104         int ret;
105
106         do {
107                 ret = fcntl(fd, cmd, arg);
108         } while (ret == -1 && errno == EINTR);
109         return ret;
110 }
111
112 /*******************************************************************
113 A fcntl wrapper that will deal with EINTR.
114 ********************************************************************/
115
116 int sys_fcntl_int(int fd, int cmd, int arg)
117 {
118         int ret;
119
120         do {
121                 ret = fcntl(fd, cmd, arg);
122         } while (ret == -1 && errno == EINTR);
123         return ret;
124 }
125
126 /****************************************************************************
127  Return the best approximation to a 'create time' under UNIX from a stat
128  structure.
129 ****************************************************************************/
130
131 static struct timespec calc_create_time_stat(const struct stat *st)
132 {
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);
137
138         ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
139         ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
140
141         if(!null_timespec(ret1)) {
142                 return ret1;
143         }
144
145         /*
146          * One of ctime, mtime or atime was zero (probably atime).
147          * Just return MIN(ctime, mtime).
148          */
149         return ret;
150 }
151
152 /****************************************************************************
153  Return the best approximation to a 'create time' under UNIX from a stat_ex
154  structure.
155 ****************************************************************************/
156
157 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
158 {
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;
163
164         ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
165         ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
166
167         if(!null_timespec(ret1)) {
168                 return ret1;
169         }
170
171         /*
172          * One of ctime, mtime or atime was zero (probably atime).
173          * Just return MIN(ctime, mtime).
174          */
175         return ret;
176 }
177
178 /****************************************************************************
179  Return the 'create time' from a stat struct if it exists (birthtime) or else
180  use the best approximation.
181 ****************************************************************************/
182
183 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
184                                  bool fake_dir_create_times)
185 {
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;
190         }
191
192         dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
193
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
206
207         /* Deal with systems that don't initialize birthtime correctly.
208          * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
209          */
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;
213         }
214 }
215
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 ****************************************************************************/
221
222 void update_stat_ex_mtime(struct stat_ex *dst,
223                                 struct timespec write_ts)
224 {
225         dst->st_ex_mtime = write_ts;
226
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);
230         }
231 }
232
233 void update_stat_ex_create_time(struct stat_ex *dst,
234                                 struct timespec create_time)
235 {
236         dst->st_ex_btime = create_time;
237         dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
238 }
239
240 void update_stat_ex_from_saved_stat(struct stat_ex *dst,
241                                     const struct stat_ex *src)
242 {
243         if (!VALID_STAT(*src)) {
244                 return;
245         }
246
247         if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME)) {
248                 update_stat_ex_create_time(dst, src->st_ex_btime);
249         }
250 }
251
252 void init_stat_ex_from_stat (struct stat_ex *dst,
253                             const struct stat *src,
254                             bool fake_dir_create_times)
255 {
256         dst->st_ex_dev = src->st_dev;
257         dst->st_ex_ino = src->st_ino;
258         dst->st_ex_mode = src->st_mode;
259         dst->st_ex_nlink = src->st_nlink;
260         dst->st_ex_uid = src->st_uid;
261         dst->st_ex_gid = src->st_gid;
262         dst->st_ex_rdev = src->st_rdev;
263         dst->st_ex_size = src->st_size;
264         dst->st_ex_atime = get_atimespec(src);
265         dst->st_ex_mtime = get_mtimespec(src);
266         dst->st_ex_ctime = get_ctimespec(src);
267         dst->st_ex_iflags = 0;
268         make_create_timespec(src, dst, fake_dir_create_times);
269 #ifdef HAVE_STAT_ST_BLKSIZE
270         dst->st_ex_blksize = src->st_blksize;
271 #else
272         dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
273 #endif
274
275 #ifdef HAVE_STAT_ST_BLOCKS
276         dst->st_ex_blocks = src->st_blocks;
277 #else
278         dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
279 #endif
280
281 #ifdef HAVE_STAT_ST_FLAGS
282         dst->st_ex_flags = src->st_flags;
283 #else
284         dst->st_ex_flags = 0;
285 #endif
286 }
287
288 /*******************************************************************
289 A stat() wrapper.
290 ********************************************************************/
291
292 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
293              bool fake_dir_create_times)
294 {
295         int ret;
296         struct stat statbuf;
297         ret = stat(fname, &statbuf);
298         if (ret == 0) {
299                 /* we always want directories to appear zero size */
300                 if (S_ISDIR(statbuf.st_mode)) {
301                         statbuf.st_size = 0;
302                 }
303                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
304         }
305         return ret;
306 }
307
308 /*******************************************************************
309  An fstat() wrapper.
310 ********************************************************************/
311
312 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
313 {
314         int ret;
315         struct stat statbuf;
316         ret = fstat(fd, &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;
321                 }
322                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
323         }
324         return ret;
325 }
326
327 /*******************************************************************
328  An lstat() wrapper.
329 ********************************************************************/
330
331 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
332               bool fake_dir_create_times)
333 {
334         int ret;
335         struct stat statbuf;
336         ret = lstat(fname, &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;
341                 }
342                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
343         }
344         return ret;
345 }
346
347 /*******************************************************************
348  An fstatat() wrapper.
349 ********************************************************************/
350
351 int sys_fstatat(int fd,
352                 const char *pathname,
353                 SMB_STRUCT_STAT *sbuf,
354                 int flags,
355                 bool fake_dir_create_times)
356 {
357         int ret;
358         struct stat statbuf;
359
360         ret = fstatat(fd, pathname, &statbuf, flags);
361         if (ret != 0) {
362                 return -1;
363         }
364
365         /* we always want directories to appear zero size */
366         if (S_ISDIR(statbuf.st_mode)) {
367                 statbuf.st_size = 0;
368         }
369         init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
370         return 0;
371 }
372
373 /*******************************************************************
374  An posix_fallocate() wrapper.
375 ********************************************************************/
376 int sys_posix_fallocate(int fd, off_t offset, off_t len)
377 {
378 #if defined(HAVE_POSIX_FALLOCATE)
379         return posix_fallocate(fd, offset, len);
380 #elif defined(F_RESVSP64)
381         /* this handles XFS on IRIX */
382         struct flock64 fl;
383         off_t new_len = offset + len;
384         int ret;
385         struct stat64 sbuf;
386
387         /* unlikely to get a too large file on a 64bit system but ... */
388         if (new_len < 0)
389                 return EFBIG;
390
391         fl.l_whence = SEEK_SET;
392         fl.l_start = offset;
393         fl.l_len = len;
394
395         ret=fcntl(fd, F_RESVSP64, &fl);
396
397         if (ret != 0)
398                 return errno;
399
400         /* Make sure the file gets enlarged after we allocated space: */
401         fstat64(fd, &sbuf);
402         if (new_len > sbuf.st_size)
403                 ftruncate64(fd, new_len);
404         return 0;
405 #else
406         return ENOSYS;
407 #endif
408 }
409
410 /*******************************************************************
411  An fallocate() function that matches the semantics of the Linux one.
412 ********************************************************************/
413
414 #ifdef HAVE_LINUX_FALLOC_H
415 #include <linux/falloc.h>
416 #endif
417
418 int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len)
419 {
420 #if defined(HAVE_LINUX_FALLOCATE)
421         int lmode = 0;
422
423         if (mode & VFS_FALLOCATE_FL_KEEP_SIZE) {
424                 lmode |= FALLOC_FL_KEEP_SIZE;
425                 mode &= ~VFS_FALLOCATE_FL_KEEP_SIZE;
426         }
427
428 #if defined(HAVE_FALLOC_FL_PUNCH_HOLE)
429         if (mode & VFS_FALLOCATE_FL_PUNCH_HOLE) {
430                 lmode |= FALLOC_FL_PUNCH_HOLE;
431                 mode &= ~VFS_FALLOCATE_FL_PUNCH_HOLE;
432         }
433 #endif  /* HAVE_FALLOC_FL_PUNCH_HOLE */
434
435         if (mode != 0) {
436                 DEBUG(2, ("unmapped fallocate flags: %lx\n",
437                       (unsigned long)mode));
438                 errno = EINVAL;
439                 return -1;
440         }
441         return fallocate(fd, lmode, offset, len);
442 #else   /* HAVE_LINUX_FALLOCATE */
443         /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
444         errno = ENOSYS;
445         return -1;
446 #endif  /* HAVE_LINUX_FALLOCATE */
447 }
448
449 /*******************************************************************
450  An fdopendir wrapper.
451 ********************************************************************/
452
453 DIR *sys_fdopendir(int fd)
454 {
455 #if defined(HAVE_FDOPENDIR)
456         return fdopendir(fd);
457 #else
458         errno = ENOSYS;
459         return NULL;
460 #endif
461 }
462
463 /*******************************************************************
464  An mknod() wrapper.
465 ********************************************************************/
466
467 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
468 {
469 #if defined(HAVE_MKNOD)
470         return mknod(path, mode, dev);
471 #else
472         /* No mknod system call. */
473         errno = ENOSYS;
474         return -1;
475 #endif
476 }
477
478 /*******************************************************************
479  A mknodat() wrapper.
480 ********************************************************************/
481
482 int sys_mknodat(int dirfd, const char *path, mode_t mode, SMB_DEV_T dev)
483 {
484 #if defined(HAVE_MKNODAT)
485         return mknodat(dirfd, path, mode, dev);
486 #else
487         /* No mknod system call. */
488         errno = ENOSYS;
489         return -1;
490 #endif
491 }
492
493 /*******************************************************************
494  System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
495  on error (malloc fail usually).
496 ********************************************************************/
497
498 char *sys_getwd(void)
499 {
500 #ifdef GETCWD_TAKES_NULL
501         return getcwd(NULL, 0);
502 #elif defined(HAVE_GETCWD)
503         char *wd = NULL, *s = NULL;
504         size_t allocated = PATH_MAX;
505
506         while (1) {
507                 s = SMB_REALLOC_ARRAY(s, char, allocated);
508                 if (s == NULL) {
509                         return NULL;
510                 }
511                 wd = getcwd(s, allocated);
512                 if (wd) {
513                         break;
514                 }
515                 if (errno != ERANGE) {
516                         int saved_errno = errno;
517                         SAFE_FREE(s);
518                         errno = saved_errno;
519                         break;
520                 }
521                 allocated *= 2;
522                 if (allocated < PATH_MAX) {
523                         SAFE_FREE(s);
524                         break;
525                 }
526         }
527         return wd;
528 #else
529         char *wd = NULL;
530         char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
531         if (s == NULL) {
532                 return NULL;
533         }
534         wd = getwd(s);
535         if (wd == NULL) {
536                 int saved_errno = errno;
537                 SAFE_FREE(s);
538                 errno = saved_errno;
539         }
540         return wd;
541 #endif
542 }
543
544 #if defined(HAVE_POSIX_CAPABILITIES)
545
546 /**************************************************************************
547  Try and abstract process capabilities (for systems that have them).
548 ****************************************************************************/
549
550 /* Set the POSIX capabilities needed for the given purpose into the effective
551  * capability set of the current process. Make sure they are always removed
552  * from the inheritable set, because there is no circumstance in which our
553  * children should inherit our elevated privileges.
554  */
555 static bool set_process_capability(enum smbd_capability capability,
556                                    bool enable)
557 {
558         /* "5" is the number of "num_cap_vals++" below */
559         cap_value_t cap_vals[5] = {0};
560         size_t num_cap_vals = 0;
561
562         cap_t cap;
563
564 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
565         /* On Linux, make sure that any capabilities we grab are sticky
566          * across UID changes. We expect that this would allow us to keep both
567          * the effective and permitted capability sets, but as of circa 2.6.16,
568          * only the permitted set is kept. It is a bug (which we work around)
569          * that the effective set is lost, but we still require the effective
570          * set to be kept.
571          */
572         if (!prctl(PR_GET_KEEPCAPS)) {
573                 prctl(PR_SET_KEEPCAPS, 1);
574         }
575 #endif
576
577         cap = cap_get_proc();
578         if (cap == NULL) {
579                 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
580                         strerror(errno)));
581                 return False;
582         }
583
584         switch (capability) {
585                 /*
586                  * WARNING: If you add any #ifdef for a fresh
587                  * capability, bump up the array size in the
588                  * declaration of cap_vals[] above just to be
589                  * trivially safe to never overwrite cap_vals[].
590                  */
591                 case KERNEL_OPLOCK_CAPABILITY:
592 #ifdef CAP_NETWORK_MGT
593                         /* IRIX has CAP_NETWORK_MGT for oplocks. */
594                         cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
595 #endif
596                         break;
597                 case DMAPI_ACCESS_CAPABILITY:
598 #ifdef CAP_DEVICE_MGT
599                         /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
600                         cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
601 #elif CAP_MKNOD
602                         /* Linux has CAP_MKNOD for DMAPI access. */
603                         cap_vals[num_cap_vals++] = CAP_MKNOD;
604 #endif
605                         break;
606                 case LEASE_CAPABILITY:
607 #ifdef CAP_LEASE
608                         cap_vals[num_cap_vals++] = CAP_LEASE;
609 #endif
610                         break;
611                 case DAC_OVERRIDE_CAPABILITY:
612 #ifdef CAP_DAC_OVERRIDE
613                         cap_vals[num_cap_vals++] = CAP_DAC_OVERRIDE;
614 #endif
615         }
616
617         if (num_cap_vals == 0) {
618                 cap_free(cap);
619                 return True;
620         }
621
622         cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
623                 enable ? CAP_SET : CAP_CLEAR);
624
625         /* We never want to pass capabilities down to our children, so make
626          * sure they are not inherited.
627          */
628         cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
629
630         if (cap_set_proc(cap) == -1) {
631                 DBG_ERR("adding capability %d: cap_set_proc failed: %s\n",
632                         capability, strerror(errno));
633                 cap_free(cap);
634                 return False;
635         }
636         DBG_INFO("added capability %d\n", capability);
637
638         cap_free(cap);
639         return True;
640 }
641
642 #endif /* HAVE_POSIX_CAPABILITIES */
643
644 /****************************************************************************
645  Gain the oplock capability from the kernel if possible.
646 ****************************************************************************/
647
648 #if defined(HAVE_POSIX_CAPABILITIES) && defined(CAP_DAC_OVERRIDE)
649 static bool have_cap_dac_override = true;
650 #else
651 static bool have_cap_dac_override = false;
652 #endif
653
654 void set_effective_capability(enum smbd_capability capability)
655 {
656         bool ret = false;
657
658         if (capability != DAC_OVERRIDE_CAPABILITY || have_cap_dac_override) {
659 #if defined(HAVE_POSIX_CAPABILITIES)
660                 ret = set_process_capability(capability, True);
661 #endif /* HAVE_POSIX_CAPABILITIES */
662         }
663
664         /*
665          * Fallback to become_root() if CAP_DAC_OVERRIDE is not
666          * available.
667          */
668         if (capability == DAC_OVERRIDE_CAPABILITY) {
669                 if (!ret) {
670                         have_cap_dac_override = false;
671                 }
672                 if (!have_cap_dac_override) {
673                         become_root();
674                 }
675         }
676 }
677
678 void drop_effective_capability(enum smbd_capability capability)
679 {
680         if (capability != DAC_OVERRIDE_CAPABILITY || have_cap_dac_override) {
681 #if defined(HAVE_POSIX_CAPABILITIES)
682                 set_process_capability(capability, False);
683 #endif /* HAVE_POSIX_CAPABILITIES */
684         } else {
685                 unbecome_root();
686         }
687 }
688
689 /**************************************************************************
690  Wrapper for random().
691 ****************************************************************************/
692
693 long sys_random(void)
694 {
695 #if defined(HAVE_RANDOM)
696         return (long)random();
697 #elif defined(HAVE_RAND)
698         return (long)rand();
699 #else
700         DEBUG(0,("Error - no random function available !\n"));
701         exit(1);
702 #endif
703 }
704
705 /**************************************************************************
706  Wrapper for srandom().
707 ****************************************************************************/
708
709 void sys_srandom(unsigned int seed)
710 {
711 #if defined(HAVE_SRANDOM)
712         srandom(seed);
713 #elif defined(HAVE_SRAND)
714         srand(seed);
715 #else
716         DEBUG(0,("Error - no srandom function available !\n"));
717         exit(1);
718 #endif
719 }
720
721 #ifndef NGROUPS_MAX
722 #define NGROUPS_MAX 32 /* Guess... */
723 #endif
724
725 /**************************************************************************
726  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
727 ****************************************************************************/
728
729 int setgroups_max(void)
730 {
731 #if defined(SYSCONF_SC_NGROUPS_MAX)
732         int ret = sysconf(_SC_NGROUPS_MAX);
733         return (ret == -1) ? NGROUPS_MAX : ret;
734 #else
735         return NGROUPS_MAX;
736 #endif
737 }
738
739 int getgroups_max(void)
740 {
741 #if defined(DARWINOS)
742         /*
743          * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group
744          * nesting. However, The initgroups() manpage states the following:
745          * "Note that OS X supports group membership in an unlimited number
746          * of groups. The OS X kernel uses the group list stored in the process
747          * credentials only as an initial cache.  Additional group memberships
748          * are determined by communication between the operating system and the
749          * opendirectoryd daemon."
750          */
751         return INT_MAX;
752 #else
753         return setgroups_max();
754 #endif
755 }
756
757 /**************************************************************************
758  Wrap setgroups and getgroups for systems that declare getgroups() as
759  returning an array of gid_t, but actually return an array of int.
760 ****************************************************************************/
761
762 #if defined(HAVE_BROKEN_GETGROUPS)
763
764 #ifdef HAVE_BROKEN_GETGROUPS
765 #define GID_T int
766 #else
767 #define GID_T gid_t
768 #endif
769
770 static int sys_broken_getgroups(int setlen, gid_t *gidset)
771 {
772         GID_T *group_list;
773         int i, ngroups;
774
775         if(setlen == 0) {
776                 return getgroups(0, NULL);
777         }
778
779         /*
780          * Broken case. We need to allocate a
781          * GID_T array of size setlen.
782          */
783
784         if(setlen < 0) {
785                 errno = EINVAL;
786                 return -1;
787         }
788
789         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
790                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
791                 return -1;
792         }
793
794         if((ngroups = getgroups(setlen, group_list)) < 0) {
795                 int saved_errno = errno;
796                 SAFE_FREE(group_list);
797                 errno = saved_errno;
798                 return -1;
799         }
800
801         /*
802          * We're safe here as if ngroups > setlen then
803          * getgroups *must* return EINVAL.
804          * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
805          */
806
807         for(i = 0; i < ngroups; i++)
808                 gidset[i] = (gid_t)group_list[i];
809
810         SAFE_FREE(group_list);
811         return ngroups;
812 }
813
814 static int sys_broken_setgroups(int setlen, gid_t *gidset)
815 {
816         GID_T *group_list;
817         int i ;
818
819         if (setlen == 0)
820                 return 0 ;
821
822         if (setlen < 0 || setlen > setgroups_max()) {
823                 errno = EINVAL;
824                 return -1;
825         }
826
827         /*
828          * Broken case. We need to allocate a
829          * GID_T array of size setlen.
830          */
831
832         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
833                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
834                 return -1;
835         }
836
837         for(i = 0; i < setlen; i++)
838                 group_list[i] = (GID_T) gidset[i];
839
840         if(samba_setgroups(setlen, group_list) != 0) {
841                 int saved_errno = errno;
842                 SAFE_FREE(group_list);
843                 errno = saved_errno;
844                 return -1;
845         }
846
847         SAFE_FREE(group_list);
848         return 0 ;
849 }
850
851 #endif /* HAVE_BROKEN_GETGROUPS */
852
853 /* This is a list of systems that require the first GID passed to setgroups(2)
854  * to be the effective GID. If your system is one of these, add it here.
855  */
856 #if defined (FREEBSD) || defined (DARWINOS)
857 #define USE_BSD_SETGROUPS
858 #endif
859
860 #if defined(USE_BSD_SETGROUPS)
861 /* Depending on the particular BSD implementation, the first GID that is
862  * passed to setgroups(2) will either be ignored or will set the credential's
863  * effective GID. In either case, the right thing to do is to guarantee that
864  * gidset[0] is the effective GID.
865  */
866 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
867 {
868         gid_t *new_gidset = NULL;
869         int max;
870         int ret;
871
872         /* setgroups(2) will fail with EINVAL if we pass too many groups. */
873         max = setgroups_max();
874
875         /* No group list, just make sure we are setting the effective GID. */
876         if (setlen == 0) {
877                 return samba_setgroups(1, &primary_gid);
878         }
879
880         /* If the primary gid is not the first array element, grow the array
881          * and insert it at the front.
882          */
883         if (gidset[0] != primary_gid) {
884                 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
885                 if (new_gidset == NULL) {
886                         return -1;
887                 }
888
889                 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
890                 new_gidset[0] = primary_gid;
891                 setlen++;
892         }
893
894         if (setlen > max) {
895                 DEBUG(3, ("forced to truncate group list from %d to %d\n",
896                         setlen, max));
897                 setlen = max;
898         }
899
900 #if defined(HAVE_BROKEN_GETGROUPS)
901         ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
902 #else
903         ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
904 #endif
905
906         if (new_gidset) {
907                 int errsav = errno;
908                 SAFE_FREE(new_gidset);
909                 errno = errsav;
910         }
911
912         return ret;
913 }
914
915 #endif /* USE_BSD_SETGROUPS */
916
917 /**************************************************************************
918  Wrapper for getgroups. Deals with broken (int) case.
919 ****************************************************************************/
920
921 int sys_getgroups(int setlen, gid_t *gidset)
922 {
923 #if defined(HAVE_BROKEN_GETGROUPS)
924         return sys_broken_getgroups(setlen, gidset);
925 #else
926         return getgroups(setlen, gidset);
927 #endif
928 }
929
930 /**************************************************************************
931  Wrapper for setgroups. Deals with broken (int) case and BSD case.
932 ****************************************************************************/
933
934 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
935 {
936 #if !defined(HAVE_SETGROUPS)
937         errno = ENOSYS;
938         return -1;
939 #endif /* HAVE_SETGROUPS */
940
941 #if defined(USE_BSD_SETGROUPS)
942         return sys_bsd_setgroups(primary_gid, setlen, gidset);
943 #elif defined(HAVE_BROKEN_GETGROUPS)
944         return sys_broken_setgroups(setlen, gidset);
945 #else
946         return samba_setgroups(setlen, gidset);
947 #endif
948 }
949
950 /****************************************************************************
951  Return the major devicenumber for UNIX extensions.
952 ****************************************************************************/
953
954 uint32_t unix_dev_major(SMB_DEV_T dev)
955 {
956 #if defined(HAVE_DEVICE_MAJOR_FN)
957         return (uint32_t)major(dev);
958 #else
959         return (uint32_t)(dev >> 8);
960 #endif
961 }
962
963 /****************************************************************************
964  Return the minor devicenumber for UNIX extensions.
965 ****************************************************************************/
966
967 uint32_t unix_dev_minor(SMB_DEV_T dev)
968 {
969 #if defined(HAVE_DEVICE_MINOR_FN)
970         return (uint32_t)minor(dev);
971 #else
972         return (uint32_t)(dev & 0xff);
973 #endif
974 }
975
976 /**************************************************************************
977  Wrapper for realpath.
978 ****************************************************************************/
979
980 char *sys_realpath(const char *path)
981 {
982         char *result;
983
984 #ifdef REALPATH_TAKES_NULL
985         result = realpath(path, NULL);
986 #else
987         result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
988         if (result) {
989                 char *resolved_path = realpath(path, result);
990                 if (!resolved_path) {
991                         SAFE_FREE(result);
992                 } else {
993                         /* SMB_ASSERT(result == resolved_path) ? */
994                         result = resolved_path;
995                 }
996         }
997 #endif
998         return result;
999 }
1000
1001 #if 0
1002 /*******************************************************************
1003  Return the number of CPUs.
1004 ********************************************************************/
1005
1006 int sys_get_number_of_cores(void)
1007 {
1008         int ret = -1;
1009
1010 #if defined(HAVE_SYSCONF)
1011 #if defined(_SC_NPROCESSORS_ONLN)
1012         ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
1013 #endif
1014 #if defined(_SC_NPROCESSORS_CONF)
1015         if (ret < 1) {
1016                 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
1017         }
1018 #endif
1019 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
1020         int name[2];
1021         unsigned int len = sizeof(ret);
1022
1023         name[0] = CTL_HW;
1024 #if defined(HW_AVAILCPU)
1025         name[1] = HW_AVAILCPU;
1026
1027         if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
1028                 ret = -1;
1029         }
1030 #endif
1031 #if defined(HW_NCPU)
1032         if(ret < 1) {
1033                 name[0] = CTL_HW;
1034                 name[1] = HW_NCPU;
1035                 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
1036                         ret = -1;
1037                 }
1038         }
1039 #endif
1040 #endif
1041         if (ret < 1) {
1042                 ret = 1;
1043         }
1044         return ret;
1045 }
1046 #endif
1047
1048 bool sys_have_proc_fds(void)
1049 {
1050         static bool checked = false;
1051         static bool have_proc_fds = false;
1052         struct stat sb;
1053         int ret;
1054
1055         if (checked) {
1056                 return have_proc_fds;
1057         }
1058
1059         ret = stat("/proc/self/fd/0", &sb);
1060         have_proc_fds = (ret == 0);
1061         checked = true;
1062
1063         return have_proc_fds;
1064 }
1065
1066 char *sys_proc_fd_path(int fd, struct sys_proc_fd_path_buf *buf)
1067 {
1068         int written =
1069                 snprintf(buf->buf, sizeof(buf->buf), "/proc/self/fd/%d", fd);
1070
1071         SMB_ASSERT(sys_have_proc_fds() && (written >= 0));
1072
1073         return buf->buf;
1074 }