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