Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/lib/system.c
Line
Count
Source
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
0
{
60
0
  ssize_t ret;
61
62
0
  do {
63
0
    ret = send(s, msg, len, flags);
64
0
  } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
65
66
0
  return ret;
67
0
}
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
0
{
76
0
  ssize_t ret;
77
78
0
  do {
79
0
    ret = recvfrom(s, buf, len, flags, from, fromlen);
80
0
  } while (ret == -1 && (errno == EINTR));
81
0
  return ret;
82
0
}
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
0
{
90
0
  int ret;
91
92
0
  do {
93
0
    ret = fcntl(fd, cmd, arg);
94
0
  } while (ret == -1 && errno == EINTR);
95
0
  return ret;
96
0
}
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
0
{
104
0
  int ret;
105
106
0
  do {
107
0
    ret = fcntl(fd, cmd, arg);
108
0
  } while (ret == -1 && errno == EINTR);
109
0
  return ret;
110
0
}
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
0
{
118
0
  int ret;
119
120
0
  do {
121
0
    ret = fcntl(fd, cmd, arg);
122
0
  } while (ret == -1 && errno == EINTR);
123
0
  return ret;
124
0
}
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
200k
{
133
200k
  struct timespec ret, ret1;
134
200k
  struct timespec c_time = get_ctimespec(st);
135
200k
  struct timespec m_time = get_mtimespec(st);
136
200k
  struct timespec a_time = get_atimespec(st);
137
138
200k
  ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
139
200k
  ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
140
141
200k
  if(!null_timespec(ret1)) {
142
200k
    return ret1;
143
200k
  }
144
145
  /*
146
   * One of ctime, mtime or atime was zero (probably atime).
147
   * Just return MIN(ctime, mtime).
148
   */
149
0
  return ret;
150
200k
}
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
0
{
159
0
  struct timespec ret, ret1;
160
0
  struct timespec c_time = st->st_ex_ctime;
161
0
  struct timespec m_time = st->st_ex_mtime;
162
0
  struct timespec a_time = st->st_ex_atime;
163
164
0
  ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
165
0
  ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
166
167
0
  if(!null_timespec(ret1)) {
168
0
    return ret1;
169
0
  }
170
171
  /*
172
   * One of ctime, mtime or atime was zero (probably atime).
173
   * Just return MIN(ctime, mtime).
174
   */
175
0
  return ret;
176
0
}
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
200k
{
186
200k
  if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
187
0
    dst->st_ex_btime.tv_sec = 315493200L;          /* 1/1/1980 */
188
0
    dst->st_ex_btime.tv_nsec = 0;
189
0
    return;
190
0
  }
191
192
200k
  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
200k
  dst->st_ex_btime = calc_create_time_stat(pst);
204
200k
  dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
205
200k
#endif
206
207
  /* Deal with systems that don't initialize birthtime correctly.
208
   * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
209
   */
210
200k
  if (null_timespec(dst->st_ex_btime)) {
211
0
    dst->st_ex_btime = calc_create_time_stat(pst);
212
0
    dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
213
0
  }
214
200k
}
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
0
{
225
0
  dst->st_ex_mtime = write_ts;
226
227
  /* We may have to recalculate btime. */
228
0
  if (dst->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME) {
229
0
    dst->st_ex_btime = calc_create_time_stat_ex(dst);
230
0
  }
231
0
}
232
233
void update_stat_ex_create_time(struct stat_ex *dst,
234
                                struct timespec create_time)
235
0
{
236
0
  dst->st_ex_btime = create_time;
237
0
  dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
238
0
}
239
240
void update_stat_ex_from_saved_stat(struct stat_ex *dst,
241
            const struct stat_ex *src)
242
0
{
243
0
  if (!VALID_STAT(*src)) {
244
0
    return;
245
0
  }
246
247
0
  if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME)) {
248
0
    update_stat_ex_create_time(dst, src->st_ex_btime);
249
0
  }
250
0
}
251
252
void copy_stat_ex_timestamps(struct stat_ex *st,
253
           const struct smb_file_time *ft)
254
0
{
255
0
  if (!is_omit_timespec(&ft->atime)) {
256
0
    st->st_ex_atime = ft->atime;
257
0
  }
258
259
0
  if (!is_omit_timespec(&ft->create_time)) {
260
0
    st->st_ex_btime = ft->create_time;
261
0
  }
262
263
0
  if (!is_omit_timespec(&ft->ctime)) {
264
0
    st->st_ex_ctime = ft->ctime;
265
0
  }
266
267
0
  if (!is_omit_timespec(&ft->mtime)) {
268
0
    st->st_ex_mtime = ft->mtime;
269
0
  }
270
0
}
271
272
void init_stat_ex_from_stat (struct stat_ex *dst,
273
          const struct stat *src,
274
          bool fake_dir_create_times)
275
200k
{
276
200k
  dst->st_ex_dev = src->st_dev;
277
200k
  dst->st_ex_ino = src->st_ino;
278
200k
  dst->st_ex_mode = src->st_mode;
279
200k
  dst->st_ex_nlink = src->st_nlink;
280
200k
  dst->st_ex_uid = src->st_uid;
281
200k
  dst->st_ex_gid = src->st_gid;
282
200k
  dst->st_ex_rdev = src->st_rdev;
283
200k
  dst->st_ex_size = src->st_size;
284
200k
  dst->st_ex_atime = get_atimespec(src);
285
200k
  dst->st_ex_mtime = get_mtimespec(src);
286
200k
  dst->st_ex_ctime = get_ctimespec(src);
287
200k
  dst->st_ex_iflags = 0;
288
200k
  make_create_timespec(src, dst, fake_dir_create_times);
289
200k
#ifdef HAVE_STAT_ST_BLKSIZE
290
200k
  dst->st_ex_blksize = src->st_blksize;
291
#else
292
  dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
293
#endif
294
295
200k
#ifdef HAVE_STAT_ST_BLOCKS
296
200k
  dst->st_ex_blocks = src->st_blocks;
297
#else
298
  dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
299
#endif
300
301
#ifdef HAVE_STAT_ST_FLAGS
302
  dst->st_ex_flags = src->st_flags;
303
#else
304
200k
  dst->st_ex_flags = 0;
305
200k
#endif
306
200k
}
307
308
/*******************************************************************
309
A stat() wrapper.
310
********************************************************************/
311
312
int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
313
       bool fake_dir_create_times)
314
0
{
315
0
  int ret;
316
0
  struct stat statbuf;
317
0
  ret = stat(fname, &statbuf);
318
0
  if (ret == 0) {
319
    /* we always want directories to appear zero size */
320
0
    if (S_ISDIR(statbuf.st_mode)) {
321
0
      statbuf.st_size = 0;
322
0
    }
323
0
    init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
324
0
  }
325
0
  return ret;
326
0
}
327
328
/*******************************************************************
329
 An fstat() wrapper.
330
********************************************************************/
331
332
int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
333
200k
{
334
200k
  int ret;
335
200k
  struct stat statbuf;
336
200k
  ret = fstat(fd, &statbuf);
337
200k
  if (ret == 0) {
338
    /* we always want directories to appear zero size */
339
200k
    if (S_ISDIR(statbuf.st_mode)) {
340
0
      statbuf.st_size = 0;
341
0
    }
342
200k
    init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
343
200k
  }
344
200k
  return ret;
345
200k
}
346
347
/*******************************************************************
348
 An lstat() wrapper.
349
********************************************************************/
350
351
int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
352
        bool fake_dir_create_times)
353
0
{
354
0
  int ret;
355
0
  struct stat statbuf;
356
0
  ret = lstat(fname, &statbuf);
357
0
  if (ret == 0) {
358
    /* we always want directories to appear zero size */
359
0
    if (S_ISDIR(statbuf.st_mode)) {
360
0
      statbuf.st_size = 0;
361
0
    }
362
0
    init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
363
0
  }
364
0
  return ret;
365
0
}
366
367
/*******************************************************************
368
 An fstatat() wrapper.
369
********************************************************************/
370
371
int sys_fstatat(int fd,
372
    const char *pathname,
373
    SMB_STRUCT_STAT *sbuf,
374
    int flags,
375
    bool fake_dir_create_times)
376
0
{
377
0
  int ret;
378
0
  struct stat statbuf;
379
380
0
  ret = fstatat(fd, pathname, &statbuf, flags);
381
0
  if (ret != 0) {
382
0
    return -1;
383
0
  }
384
385
  /* we always want directories to appear zero size */
386
0
  if (S_ISDIR(statbuf.st_mode)) {
387
0
    statbuf.st_size = 0;
388
0
  }
389
0
  init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
390
0
  return 0;
391
0
}
392
393
/*******************************************************************
394
 An posix_fallocate() wrapper.
395
********************************************************************/
396
int sys_posix_fallocate(int fd, off_t offset, off_t len)
397
0
{
398
0
#if defined(HAVE_POSIX_FALLOCATE)
399
0
  return posix_fallocate(fd, offset, len);
400
#elif defined(F_RESVSP64)
401
  /* this handles XFS on IRIX */
402
  struct flock64 fl;
403
  off_t new_len = offset + len;
404
  int ret;
405
  struct stat64 sbuf;
406
407
  /* unlikely to get a too large file on a 64bit system but ... */
408
  if (new_len < 0)
409
    return EFBIG;
410
411
  fl.l_whence = SEEK_SET;
412
  fl.l_start = offset;
413
  fl.l_len = len;
414
415
  ret=fcntl(fd, F_RESVSP64, &fl);
416
417
  if (ret != 0)
418
    return errno;
419
420
  /* Make sure the file gets enlarged after we allocated space: */
421
  fstat64(fd, &sbuf);
422
  if (new_len > sbuf.st_size)
423
    ftruncate64(fd, new_len);
424
  return 0;
425
#else
426
  return ENOSYS;
427
#endif
428
0
}
429
430
/*******************************************************************
431
 An fallocate() function that matches the semantics of the Linux one.
432
********************************************************************/
433
434
#ifdef HAVE_LINUX_FALLOC_H
435
#include <linux/falloc.h>
436
#endif
437
438
int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len)
439
0
{
440
0
#if defined(HAVE_LINUX_FALLOCATE)
441
0
  int lmode = 0;
442
443
0
  if (mode & VFS_FALLOCATE_FL_KEEP_SIZE) {
444
0
    lmode |= FALLOC_FL_KEEP_SIZE;
445
0
    mode &= ~VFS_FALLOCATE_FL_KEEP_SIZE;
446
0
  }
447
448
0
#if defined(HAVE_FALLOC_FL_PUNCH_HOLE)
449
0
  if (mode & VFS_FALLOCATE_FL_PUNCH_HOLE) {
450
0
    lmode |= FALLOC_FL_PUNCH_HOLE;
451
0
    mode &= ~VFS_FALLOCATE_FL_PUNCH_HOLE;
452
0
  }
453
0
#endif  /* HAVE_FALLOC_FL_PUNCH_HOLE */
454
455
0
  if (mode != 0) {
456
0
    DEBUG(2, ("unmapped fallocate flags: %lx\n",
457
0
          (unsigned long)mode));
458
0
    errno = EINVAL;
459
0
    return -1;
460
0
  }
461
0
  return fallocate(fd, lmode, offset, len);
462
#else /* HAVE_LINUX_FALLOCATE */
463
  /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
464
  errno = ENOSYS;
465
  return -1;
466
#endif  /* HAVE_LINUX_FALLOCATE */
467
0
}
468
469
/*******************************************************************
470
 An fdopendir wrapper.
471
********************************************************************/
472
473
DIR *sys_fdopendir(int fd)
474
0
{
475
0
#if defined(HAVE_FDOPENDIR)
476
0
  return fdopendir(fd);
477
#else
478
  errno = ENOSYS;
479
  return NULL;
480
#endif
481
0
}
482
483
/*******************************************************************
484
 An mknod() wrapper.
485
********************************************************************/
486
487
int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
488
0
{
489
0
#if defined(HAVE_MKNOD)
490
0
  return mknod(path, mode, dev);
491
#else
492
  /* No mknod system call. */
493
  errno = ENOSYS;
494
  return -1;
495
#endif
496
0
}
497
498
/*******************************************************************
499
 A mknodat() wrapper.
500
********************************************************************/
501
502
int sys_mknodat(int dirfd, const char *path, mode_t mode, SMB_DEV_T dev)
503
0
{
504
0
#if defined(HAVE_MKNODAT)
505
0
  return mknodat(dirfd, path, mode, dev);
506
#else
507
  /* No mknod system call. */
508
  errno = ENOSYS;
509
  return -1;
510
#endif
511
0
}
512
513
/*******************************************************************
514
 System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
515
 on error (malloc fail usually).
516
********************************************************************/
517
518
char *sys_getwd(void)
519
0
{
520
0
#ifdef GETCWD_TAKES_NULL
521
0
  return getcwd(NULL, 0);
522
#elif defined(HAVE_GETCWD)
523
  char *wd = NULL, *s = NULL;
524
  size_t allocated = PATH_MAX;
525
526
  while (1) {
527
    s = SMB_REALLOC_ARRAY(s, char, allocated);
528
    if (s == NULL) {
529
      return NULL;
530
    }
531
    wd = getcwd(s, allocated);
532
    if (wd) {
533
      break;
534
    }
535
    if (errno != ERANGE) {
536
      int saved_errno = errno;
537
      SAFE_FREE(s);
538
      errno = saved_errno;
539
      break;
540
    }
541
    allocated *= 2;
542
    if (allocated < PATH_MAX) {
543
      SAFE_FREE(s);
544
      break;
545
    }
546
  }
547
  return wd;
548
#else
549
  char *wd = NULL;
550
  char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
551
  if (s == NULL) {
552
    return NULL;
553
  }
554
  wd = getwd(s);
555
  if (wd == NULL) {
556
    int saved_errno = errno;
557
    SAFE_FREE(s);
558
    errno = saved_errno;
559
  }
560
  return wd;
561
#endif
562
0
}
563
564
#if defined(HAVE_POSIX_CAPABILITIES)
565
566
static bool set_one_cap(cap_value_t val, bool enable)
567
0
{
568
0
  cap_t cap;
569
0
  cap_flag_value_t flag = enable ? CAP_SET : CAP_CLEAR;
570
0
  int ret;
571
572
0
  cap = cap_get_proc();
573
0
  if (cap == NULL) {
574
0
    DBG_ERR("cap_get_proc failed: %s\n", strerror(errno));
575
0
    return false;
576
0
  }
577
578
0
  ret = cap_set_flag(cap, CAP_EFFECTIVE, 1, &val, flag);
579
0
  SMB_ASSERT(ret == 0);
580
581
  /*
582
   * We never want to pass capabilities down to our children, so
583
   * make sure they are not inherited.
584
   */
585
0
  ret = cap_set_flag(cap, CAP_INHERITABLE, 1, &val, CAP_CLEAR);
586
0
  SMB_ASSERT(ret == 0);
587
588
0
  ret = cap_set_proc(cap);
589
0
  if (ret == -1) {
590
0
    int err = errno;
591
592
0
    DBG_ERR("%s capability %jd: cap_set_proc failed: %s\n",
593
0
      enable ? "adding" : "dropping",
594
0
      (intmax_t)val,
595
0
      strerror(errno));
596
597
0
    cap_free(cap);
598
0
    errno = err;
599
0
    return false;
600
0
  }
601
602
0
  DBG_INFO("%s capability %jd\n",
603
0
     enable ? "added" : "dropped",
604
0
     (intmax_t)val);
605
606
0
  cap_free(cap);
607
0
  return true;
608
0
}
609
610
#endif /* HAVE_POSIX_CAPABILITIES */
611
612
void set_dmapi_capability(bool enable)
613
0
{
614
0
#if defined(HAVE_POSIX_CAPABILITIES) && defined(CAP_MKNOD)
615
  /*
616
   * Ignore result, we'll get EACCES/EPERM later
617
   */
618
0
  (void)set_one_cap(CAP_MKNOD, enable);
619
0
#endif
620
0
  return;
621
0
}
622
623
void set_dac_override_capability(bool enable)
624
0
{
625
#if !defined(HAVE_POSIX_CAPABILITIES) || !defined(CAP_DAC_OVERRIDE)
626
627
/*
628
 * Use [un]become_root()
629
 */
630
#define have_cap_dac_override false
631
632
#else
633
  /*
634
   * Only try this once
635
   */
636
0
  static bool have_cap_dac_override = true;
637
0
  if (have_cap_dac_override) {
638
0
    have_cap_dac_override = set_one_cap(CAP_DAC_OVERRIDE, enable);
639
640
0
    if (!enable) {
641
      /*
642
       * Dropping caps again must always work.
643
       */
644
0
      SMB_ASSERT(have_cap_dac_override);
645
0
    }
646
0
  }
647
0
#endif
648
649
0
  if (!have_cap_dac_override) {
650
    /*
651
     * Fallback if CAP_DAC_OVERRIDE is not available
652
     */
653
0
    if (enable) {
654
0
      become_root();
655
0
    } else {
656
0
      unbecome_root();
657
0
    }
658
0
  }
659
0
}
660
661
/**************************************************************************
662
 Wrapper for random().
663
****************************************************************************/
664
665
long sys_random(void)
666
0
{
667
0
#if defined(HAVE_RANDOM)
668
0
  return (long)random();
669
#elif defined(HAVE_RAND)
670
  return (long)rand();
671
#else
672
  DEBUG(0,("Error - no random function available !\n"));
673
  exit(1);
674
#endif
675
0
}
676
677
/**************************************************************************
678
 Wrapper for srandom().
679
****************************************************************************/
680
681
void sys_srandom(unsigned int seed)
682
0
{
683
0
#if defined(HAVE_SRANDOM)
684
0
  srandom(seed);
685
#elif defined(HAVE_SRAND)
686
  srand(seed);
687
#else
688
  DEBUG(0,("Error - no srandom function available !\n"));
689
  exit(1);
690
#endif
691
0
}
692
693
#ifndef NGROUPS_MAX
694
#define NGROUPS_MAX 32 /* Guess... */
695
#endif
696
697
/**************************************************************************
698
 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
699
****************************************************************************/
700
701
int setgroups_max(void)
702
0
{
703
0
#if defined(SYSCONF_SC_NGROUPS_MAX)
704
0
  int ret = sysconf(_SC_NGROUPS_MAX);
705
0
  return (ret == -1) ? NGROUPS_MAX : ret;
706
#else
707
  return NGROUPS_MAX;
708
#endif
709
0
}
710
711
int getgroups_max(void)
712
0
{
713
#if defined(DARWINOS)
714
  /*
715
   * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group
716
   * nesting. However, The initgroups() manpage states the following:
717
   * "Note that OS X supports group membership in an unlimited number
718
   * of groups. The OS X kernel uses the group list stored in the process
719
   * credentials only as an initial cache.  Additional group memberships
720
   * are determined by communication between the operating system and the
721
   * opendirectoryd daemon."
722
   */
723
  return INT_MAX;
724
#else
725
0
  return setgroups_max();
726
0
#endif
727
0
}
728
729
/**************************************************************************
730
 Wrap setgroups and getgroups for systems that declare getgroups() as
731
 returning an array of gid_t, but actually return an array of int.
732
****************************************************************************/
733
734
#if defined(HAVE_BROKEN_GETGROUPS)
735
736
#ifdef HAVE_BROKEN_GETGROUPS
737
#define GID_T int
738
#else
739
#define GID_T gid_t
740
#endif
741
742
static int sys_broken_getgroups(int setlen, gid_t *gidset)
743
{
744
  GID_T *group_list;
745
  int i, ngroups;
746
747
  if(setlen == 0) {
748
    return getgroups(0, NULL);
749
  }
750
751
  /*
752
   * Broken case. We need to allocate a
753
   * GID_T array of size setlen.
754
   */
755
756
  if(setlen < 0) {
757
    errno = EINVAL;
758
    return -1;
759
  }
760
761
  if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
762
    DEBUG(0,("sys_getgroups: Malloc fail.\n"));
763
    return -1;
764
  }
765
766
  if((ngroups = getgroups(setlen, group_list)) < 0) {
767
    int saved_errno = errno;
768
    SAFE_FREE(group_list);
769
    errno = saved_errno;
770
    return -1;
771
  }
772
773
  /*
774
   * We're safe here as if ngroups > setlen then
775
   * getgroups *must* return EINVAL.
776
   * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
777
   */
778
779
  for(i = 0; i < ngroups; i++)
780
    gidset[i] = (gid_t)group_list[i];
781
782
  SAFE_FREE(group_list);
783
  return ngroups;
784
}
785
786
static int sys_broken_setgroups(int setlen, gid_t *gidset)
787
{
788
  GID_T *group_list;
789
  int i ;
790
791
  if (setlen == 0)
792
    return 0 ;
793
794
  if (setlen < 0 || setlen > setgroups_max()) {
795
    errno = EINVAL;
796
    return -1;
797
  }
798
799
  /*
800
   * Broken case. We need to allocate a
801
   * GID_T array of size setlen.
802
   */
803
804
  if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
805
    DEBUG(0,("sys_setgroups: Malloc fail.\n"));
806
    return -1;
807
  }
808
809
  for(i = 0; i < setlen; i++)
810
    group_list[i] = (GID_T) gidset[i];
811
812
  if(samba_setgroups(setlen, group_list) != 0) {
813
    int saved_errno = errno;
814
    SAFE_FREE(group_list);
815
    errno = saved_errno;
816
    return -1;
817
  }
818
819
  SAFE_FREE(group_list);
820
  return 0 ;
821
}
822
823
#endif /* HAVE_BROKEN_GETGROUPS */
824
825
/* This is a list of systems that require the first GID passed to setgroups(2)
826
 * to be the effective GID. If your system is one of these, add it here.
827
 */
828
#if defined (FREEBSD) || defined (DARWINOS)
829
#define USE_BSD_SETGROUPS
830
#endif
831
832
#if defined(USE_BSD_SETGROUPS)
833
/* Depending on the particular BSD implementation, the first GID that is
834
 * passed to setgroups(2) will either be ignored or will set the credential's
835
 * effective GID. In either case, the right thing to do is to guarantee that
836
 * gidset[0] is the effective GID.
837
 */
838
static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
839
{
840
  gid_t *new_gidset = NULL;
841
  int max;
842
  int ret;
843
844
  /* setgroups(2) will fail with EINVAL if we pass too many groups. */
845
  max = setgroups_max();
846
847
  /* No group list, just make sure we are setting the effective GID. */
848
  if (setlen == 0) {
849
    return samba_setgroups(1, &primary_gid);
850
  }
851
852
  /* If the primary gid is not the first array element, grow the array
853
   * and insert it at the front.
854
   */
855
  if (gidset[0] != primary_gid) {
856
          new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
857
          if (new_gidset == NULL) {
858
      return -1;
859
          }
860
861
    memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
862
    new_gidset[0] = primary_gid;
863
    setlen++;
864
  }
865
866
  if (setlen > max) {
867
    DEBUG(3, ("forced to truncate group list from %d to %d\n",
868
      setlen, max));
869
    setlen = max;
870
  }
871
872
#if defined(HAVE_BROKEN_GETGROUPS)
873
  ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
874
#else
875
  ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
876
#endif
877
878
  if (new_gidset) {
879
    int errsav = errno;
880
    SAFE_FREE(new_gidset);
881
    errno = errsav;
882
  }
883
884
  return ret;
885
}
886
887
#endif /* USE_BSD_SETGROUPS */
888
889
/**************************************************************************
890
 Wrapper for getgroups. Deals with broken (int) case.
891
****************************************************************************/
892
893
int sys_getgroups(int setlen, gid_t *gidset)
894
0
{
895
#if defined(HAVE_BROKEN_GETGROUPS)
896
  return sys_broken_getgroups(setlen, gidset);
897
#else
898
0
  return getgroups(setlen, gidset);
899
0
#endif
900
0
}
901
902
/**************************************************************************
903
 Wrapper for setgroups. Deals with broken (int) case and BSD case.
904
****************************************************************************/
905
906
int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
907
0
{
908
#if !defined(HAVE_SETGROUPS)
909
  errno = ENOSYS;
910
  return -1;
911
#endif /* HAVE_SETGROUPS */
912
913
#if defined(USE_BSD_SETGROUPS)
914
  return sys_bsd_setgroups(primary_gid, setlen, gidset);
915
#elif defined(HAVE_BROKEN_GETGROUPS)
916
  return sys_broken_setgroups(setlen, gidset);
917
#else
918
0
  return samba_setgroups(setlen, gidset);
919
0
#endif
920
0
}
921
922
/****************************************************************************
923
 Return the major devicenumber for UNIX extensions.
924
****************************************************************************/
925
926
uint32_t unix_dev_major(SMB_DEV_T dev)
927
0
{
928
0
#if defined(HAVE_DEVICE_MAJOR_FN)
929
0
        return (uint32_t)major(dev);
930
#else
931
        return (uint32_t)(dev >> 8);
932
#endif
933
0
}
934
935
/****************************************************************************
936
 Return the minor devicenumber for UNIX extensions.
937
****************************************************************************/
938
939
uint32_t unix_dev_minor(SMB_DEV_T dev)
940
0
{
941
0
#if defined(HAVE_DEVICE_MINOR_FN)
942
0
        return (uint32_t)minor(dev);
943
#else
944
        return (uint32_t)(dev & 0xff);
945
#endif
946
0
}
947
948
/**************************************************************************
949
 Wrapper for realpath.
950
****************************************************************************/
951
952
char *sys_realpath(const char *path)
953
0
{
954
0
  char *result;
955
956
0
#ifdef REALPATH_TAKES_NULL
957
0
  result = realpath(path, NULL);
958
#else
959
  result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
960
  if (result) {
961
    char *resolved_path = realpath(path, result);
962
    if (!resolved_path) {
963
      SAFE_FREE(result);
964
    } else {
965
      /* SMB_ASSERT(result == resolved_path) ? */
966
      result = resolved_path;
967
    }
968
  }
969
#endif
970
0
  return result;
971
0
}
972
973
bool sys_have_proc_fds(void)
974
0
{
975
0
  static bool checked = false;
976
0
  static bool have_proc_fds = false;
977
0
  struct stat sb;
978
0
  int ret;
979
980
0
  if (checked) {
981
0
    return have_proc_fds;
982
0
  }
983
984
0
  ret = stat("/proc/self/fd/0", &sb);
985
0
  have_proc_fds = (ret == 0);
986
0
  checked = true;
987
988
0
  return have_proc_fds;
989
0
}
990
991
char *sys_proc_fd_path(int fd, struct sys_proc_fd_path_buf *buf)
992
0
{
993
0
  int written =
994
0
    snprintf(buf->buf, sizeof(buf->buf), "/proc/self/fd/%d", fd);
995
996
0
  SMB_ASSERT(sys_have_proc_fds() && (written >= 0));
997
998
0
  return buf->buf;
999
0
}