smbd: remove itime and file_id logic and code
[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 void set_effective_capability(enum smbd_capability capability)
647 {
648 #if defined(HAVE_POSIX_CAPABILITIES)
649         set_process_capability(capability, True);
650 #endif /* HAVE_POSIX_CAPABILITIES */
651 }
652
653 void drop_effective_capability(enum smbd_capability capability)
654 {
655 #if defined(HAVE_POSIX_CAPABILITIES)
656         set_process_capability(capability, False);
657 #endif /* HAVE_POSIX_CAPABILITIES */
658 }
659
660 /**************************************************************************
661  Wrapper for random().
662 ****************************************************************************/
663
664 long sys_random(void)
665 {
666 #if defined(HAVE_RANDOM)
667         return (long)random();
668 #elif defined(HAVE_RAND)
669         return (long)rand();
670 #else
671         DEBUG(0,("Error - no random function available !\n"));
672         exit(1);
673 #endif
674 }
675
676 /**************************************************************************
677  Wrapper for srandom().
678 ****************************************************************************/
679
680 void sys_srandom(unsigned int seed)
681 {
682 #if defined(HAVE_SRANDOM)
683         srandom(seed);
684 #elif defined(HAVE_SRAND)
685         srand(seed);
686 #else
687         DEBUG(0,("Error - no srandom function available !\n"));
688         exit(1);
689 #endif
690 }
691
692 #ifndef NGROUPS_MAX
693 #define NGROUPS_MAX 32 /* Guess... */
694 #endif
695
696 /**************************************************************************
697  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
698 ****************************************************************************/
699
700 int setgroups_max(void)
701 {
702 #if defined(SYSCONF_SC_NGROUPS_MAX)
703         int ret = sysconf(_SC_NGROUPS_MAX);
704         return (ret == -1) ? NGROUPS_MAX : ret;
705 #else
706         return NGROUPS_MAX;
707 #endif
708 }
709
710 int getgroups_max(void)
711 {
712 #if defined(DARWINOS)
713         /*
714          * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group
715          * nesting. However, The initgroups() manpage states the following:
716          * "Note that OS X supports group membership in an unlimited number
717          * of groups. The OS X kernel uses the group list stored in the process
718          * credentials only as an initial cache.  Additional group memberships
719          * are determined by communication between the operating system and the
720          * opendirectoryd daemon."
721          */
722         return INT_MAX;
723 #else
724         return setgroups_max();
725 #endif
726 }
727
728 /**************************************************************************
729  Wrap setgroups and getgroups for systems that declare getgroups() as
730  returning an array of gid_t, but actuall return an array of int.
731 ****************************************************************************/
732
733 #if defined(HAVE_BROKEN_GETGROUPS)
734
735 #ifdef HAVE_BROKEN_GETGROUPS
736 #define GID_T int
737 #else
738 #define GID_T gid_t
739 #endif
740
741 static int sys_broken_getgroups(int setlen, gid_t *gidset)
742 {
743         GID_T *group_list;
744         int i, ngroups;
745
746         if(setlen == 0) {
747                 return getgroups(0, NULL);
748         }
749
750         /*
751          * Broken case. We need to allocate a
752          * GID_T array of size setlen.
753          */
754
755         if(setlen < 0) {
756                 errno = EINVAL; 
757                 return -1;
758         } 
759
760         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
761                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
762                 return -1;
763         }
764
765         if((ngroups = getgroups(setlen, group_list)) < 0) {
766                 int saved_errno = errno;
767                 SAFE_FREE(group_list);
768                 errno = saved_errno;
769                 return -1;
770         }
771
772         /*
773          * We're safe here as if ngroups > setlen then
774          * getgroups *must* return EINVAL.
775          * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
776          */
777
778         for(i = 0; i < ngroups; i++)
779                 gidset[i] = (gid_t)group_list[i];
780
781         SAFE_FREE(group_list);
782         return ngroups;
783 }
784
785 static int sys_broken_setgroups(int setlen, gid_t *gidset)
786 {
787         GID_T *group_list;
788         int i ; 
789
790         if (setlen == 0)
791                 return 0 ;
792
793         if (setlen < 0 || setlen > setgroups_max()) {
794                 errno = EINVAL; 
795                 return -1;   
796         }
797
798         /*
799          * Broken case. We need to allocate a
800          * GID_T array of size setlen.
801          */
802
803         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
804                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
805                 return -1;    
806         }
807
808         for(i = 0; i < setlen; i++) 
809                 group_list[i] = (GID_T) gidset[i]; 
810
811         if(samba_setgroups(setlen, group_list) != 0) {
812                 int saved_errno = errno;
813                 SAFE_FREE(group_list);
814                 errno = saved_errno;
815                 return -1;
816         }
817
818         SAFE_FREE(group_list);
819         return 0 ;
820 }
821
822 #endif /* HAVE_BROKEN_GETGROUPS */
823
824 /* This is a list of systems that require the first GID passed to setgroups(2)
825  * to be the effective GID. If your system is one of these, add it here.
826  */
827 #if defined (FREEBSD) || defined (DARWINOS)
828 #define USE_BSD_SETGROUPS
829 #endif
830
831 #if defined(USE_BSD_SETGROUPS)
832 /* Depending on the particular BSD implementation, the first GID that is
833  * passed to setgroups(2) will either be ignored or will set the credential's
834  * effective GID. In either case, the right thing to do is to guarantee that
835  * gidset[0] is the effective GID.
836  */
837 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
838 {
839         gid_t *new_gidset = NULL;
840         int max;
841         int ret;
842
843         /* setgroups(2) will fail with EINVAL if we pass too many groups. */
844         max = setgroups_max();
845
846         /* No group list, just make sure we are setting the efective GID. */
847         if (setlen == 0) {
848                 return samba_setgroups(1, &primary_gid);
849         }
850
851         /* If the primary gid is not the first array element, grow the array
852          * and insert it at the front.
853          */
854         if (gidset[0] != primary_gid) {
855                 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
856                 if (new_gidset == NULL) {
857                         return -1;
858                 }
859
860                 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
861                 new_gidset[0] = primary_gid;
862                 setlen++;
863         }
864
865         if (setlen > max) {
866                 DEBUG(3, ("forced to truncate group list from %d to %d\n",
867                         setlen, max));
868                 setlen = max;
869         }
870
871 #if defined(HAVE_BROKEN_GETGROUPS)
872         ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
873 #else
874         ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
875 #endif
876
877         if (new_gidset) {
878                 int errsav = errno;
879                 SAFE_FREE(new_gidset);
880                 errno = errsav;
881         }
882
883         return ret;
884 }
885
886 #endif /* USE_BSD_SETGROUPS */
887
888 /**************************************************************************
889  Wrapper for getgroups. Deals with broken (int) case.
890 ****************************************************************************/
891
892 int sys_getgroups(int setlen, gid_t *gidset)
893 {
894 #if defined(HAVE_BROKEN_GETGROUPS)
895         return sys_broken_getgroups(setlen, gidset);
896 #else
897         return getgroups(setlen, gidset);
898 #endif
899 }
900
901 /**************************************************************************
902  Wrapper for setgroups. Deals with broken (int) case and BSD case.
903 ****************************************************************************/
904
905 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
906 {
907 #if !defined(HAVE_SETGROUPS)
908         errno = ENOSYS;
909         return -1;
910 #endif /* HAVE_SETGROUPS */
911
912 #if defined(USE_BSD_SETGROUPS)
913         return sys_bsd_setgroups(primary_gid, setlen, gidset);
914 #elif defined(HAVE_BROKEN_GETGROUPS)
915         return sys_broken_setgroups(setlen, gidset);
916 #else
917         return samba_setgroups(setlen, gidset);
918 #endif
919 }
920
921 /****************************************************************************
922  Return the major devicenumber for UNIX extensions.
923 ****************************************************************************/
924
925 uint32_t unix_dev_major(SMB_DEV_T dev)
926 {
927 #if defined(HAVE_DEVICE_MAJOR_FN)
928         return (uint32_t)major(dev);
929 #else
930         return (uint32_t)(dev >> 8);
931 #endif
932 }
933
934 /****************************************************************************
935  Return the minor devicenumber for UNIX extensions.
936 ****************************************************************************/
937
938 uint32_t unix_dev_minor(SMB_DEV_T dev)
939 {
940 #if defined(HAVE_DEVICE_MINOR_FN)
941         return (uint32_t)minor(dev);
942 #else
943         return (uint32_t)(dev & 0xff);
944 #endif
945 }
946
947 /**************************************************************************
948  Wrapper for realpath.
949 ****************************************************************************/
950
951 char *sys_realpath(const char *path)
952 {
953         char *result;
954
955 #ifdef REALPATH_TAKES_NULL
956         result = realpath(path, NULL);
957 #else
958         result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
959         if (result) {
960                 char *resolved_path = realpath(path, result);
961                 if (!resolved_path) {
962                         SAFE_FREE(result);
963                 } else {
964                         /* SMB_ASSERT(result == resolved_path) ? */
965                         result = resolved_path;
966                 }
967         }
968 #endif
969         return result;
970 }
971
972 #if 0
973 /*******************************************************************
974  Return the number of CPUs.
975 ********************************************************************/
976
977 int sys_get_number_of_cores(void)
978 {
979         int ret = -1;
980
981 #if defined(HAVE_SYSCONF)
982 #if defined(_SC_NPROCESSORS_ONLN)
983         ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
984 #endif
985 #if defined(_SC_NPROCESSORS_CONF)
986         if (ret < 1) {
987                 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
988         }
989 #endif
990 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
991         int name[2];
992         unsigned int len = sizeof(ret);
993
994         name[0] = CTL_HW;
995 #if defined(HW_AVAILCPU)
996         name[1] = HW_AVAILCPU;
997
998         if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
999                 ret = -1;
1000         }
1001 #endif
1002 #if defined(HW_NCPU)
1003         if(ret < 1) {
1004                 name[0] = CTL_HW;
1005                 name[1] = HW_NCPU;
1006                 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
1007                         ret = -1;
1008                 }
1009         }
1010 #endif
1011 #endif
1012         if (ret < 1) {
1013                 ret = 1;
1014         }
1015         return ret;
1016 }
1017 #endif
1018
1019 static struct proc_fd_pattern {
1020         const char *pattern;
1021         const char *test_path;
1022 } proc_fd_patterns[] = {
1023         /* Linux */
1024         { "/proc/self/fd/%d", "/proc/self/fd/0" },
1025         { NULL, NULL },
1026 };
1027
1028 static const char *proc_fd_pattern;
1029
1030 bool sys_have_proc_fds(void)
1031 {
1032         static bool checked;
1033         static bool have_proc_fds;
1034         struct proc_fd_pattern *p = NULL;
1035         struct stat sb;
1036         int ret;
1037
1038         if (checked) {
1039                 return have_proc_fds;
1040         }
1041
1042         for (p = &proc_fd_patterns[0]; p->test_path != NULL; p++) {
1043                 ret = stat(p->test_path, &sb);
1044                 if (ret != 0) {
1045                         continue;
1046                 }
1047                 have_proc_fds = true;
1048                 proc_fd_pattern = p->pattern;
1049                 break;
1050         }
1051
1052         checked = true;
1053         return have_proc_fds;
1054 }
1055
1056 const char *sys_proc_fd_path(int fd, char *buf, size_t bufsize)
1057 {
1058         int written;
1059
1060         if (!sys_have_proc_fds()) {
1061                 return NULL;
1062         }
1063
1064 #if defined(__clang__)
1065 #pragma clang diagnostic push
1066 #pragma clang diagnostic ignored "-Wformat-nonliteral"
1067 #endif
1068         written = snprintf(buf,
1069                            bufsize,
1070                            proc_fd_pattern,
1071                            fd);
1072 #if defined(__clang__)
1073 #pragma clang diagnostic pop
1074 #endif
1075         if (written >= bufsize) {
1076                 return NULL;
1077         }
1078
1079         return buf;
1080 }