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