Coverage Report

Created: 2025-12-31 06:20

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
233k
{
133
233k
  struct timespec ret, ret1;
134
233k
  struct timespec c_time = get_ctimespec(st);
135
233k
  struct timespec m_time = get_mtimespec(st);
136
233k
  struct timespec a_time = get_atimespec(st);
137
138
233k
  ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
139
233k
  ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
140
141
233k
  if(!null_timespec(ret1)) {
142
233k
    return ret1;
143
233k
  }
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
233k
}
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
233k
{
186
233k
  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
233k
  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
233k
  dst->st_ex_btime = calc_create_time_stat(pst);
204
233k
  dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
205
233k
#endif
206
207
  /* Deal with systems that don't initialize birthtime correctly.
208
   * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
209
   */
210
233k
  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
233k
}
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
233k
{
276
233k
  dst->st_ex_dev = src->st_dev;
277
233k
  dst->st_ex_ino = src->st_ino;
278
233k
  dst->st_ex_mode = src->st_mode;
279
233k
  dst->st_ex_nlink = src->st_nlink;
280
233k
  dst->st_ex_uid = src->st_uid;
281
233k
  dst->st_ex_gid = src->st_gid;
282
233k
  dst->st_ex_rdev = src->st_rdev;
283
233k
  dst->st_ex_size = src->st_size;
284
233k
  dst->st_ex_atime = get_atimespec(src);
285
233k
  dst->st_ex_mtime = get_mtimespec(src);
286
233k
  dst->st_ex_ctime = get_ctimespec(src);
287
233k
  dst->st_ex_iflags = 0;
288
233k
  make_create_timespec(src, dst, fake_dir_create_times);
289
233k
#ifdef HAVE_STAT_ST_BLKSIZE
290
233k
  dst->st_ex_blksize = src->st_blksize;
291
#else
292
  dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
293
#endif
294
295
233k
#ifdef HAVE_STAT_ST_BLOCKS
296
233k
  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
233k
  dst->st_ex_flags = 0;
305
233k
#endif
306
233k
}
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
233k
{
334
233k
  int ret;
335
233k
  struct stat statbuf;
336
233k
  ret = fstat(fd, &statbuf);
337
233k
  if (ret == 0) {
338
    /* we always want directories to appear zero size */
339
233k
    if (S_ISDIR(statbuf.st_mode)) {
340
0
      statbuf.st_size = 0;
341
0
    }
342
233k
    init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
343
233k
  }
344
233k
  return ret;
345
233k
}
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
/**************************************************************************
567
 Try and abstract process capabilities (for systems that have them).
568
****************************************************************************/
569
570
/* Set the POSIX capabilities needed for the given purpose into the effective
571
 * capability set of the current process. Make sure they are always removed
572
 * from the inheritable set, because there is no circumstance in which our
573
 * children should inherit our elevated privileges.
574
 */
575
static bool set_process_capability(enum smbd_capability capability,
576
           bool enable)
577
0
{
578
  /* "5" is the number of "num_cap_vals++" below */
579
0
  cap_value_t cap_vals[5] = {0};
580
0
  size_t num_cap_vals = 0;
581
582
0
  cap_t cap;
583
584
0
#if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
585
  /* On Linux, make sure that any capabilities we grab are sticky
586
   * across UID changes. We expect that this would allow us to keep both
587
   * the effective and permitted capability sets, but as of circa 2.6.16,
588
   * only the permitted set is kept. It is a bug (which we work around)
589
   * that the effective set is lost, but we still require the effective
590
   * set to be kept.
591
   */
592
0
  if (!prctl(PR_GET_KEEPCAPS)) {
593
0
    prctl(PR_SET_KEEPCAPS, 1);
594
0
  }
595
0
#endif
596
597
0
  cap = cap_get_proc();
598
0
  if (cap == NULL) {
599
0
    DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
600
0
      strerror(errno)));
601
0
    return False;
602
0
  }
603
604
0
  switch (capability) {
605
    /*
606
     * WARNING: If you add any #ifdef for a fresh
607
     * capability, bump up the array size in the
608
     * declaration of cap_vals[] above just to be
609
     * trivially safe to never overwrite cap_vals[].
610
     */
611
0
    case KERNEL_OPLOCK_CAPABILITY:
612
#ifdef CAP_NETWORK_MGT
613
      /* IRIX has CAP_NETWORK_MGT for oplocks. */
614
      cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
615
#endif
616
0
      break;
617
0
    case DMAPI_ACCESS_CAPABILITY:
618
#ifdef CAP_DEVICE_MGT
619
      /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
620
      cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
621
#elif CAP_MKNOD
622
      /* Linux has CAP_MKNOD for DMAPI access. */
623
0
      cap_vals[num_cap_vals++] = CAP_MKNOD;
624
0
#endif
625
0
      break;
626
0
    case LEASE_CAPABILITY:
627
0
#ifdef CAP_LEASE
628
0
      cap_vals[num_cap_vals++] = CAP_LEASE;
629
0
#endif
630
0
      break;
631
0
    case DAC_OVERRIDE_CAPABILITY:
632
0
#ifdef CAP_DAC_OVERRIDE
633
0
      cap_vals[num_cap_vals++] = CAP_DAC_OVERRIDE;
634
0
#endif
635
0
  }
636
637
0
  if (num_cap_vals == 0) {
638
0
    cap_free(cap);
639
0
    return True;
640
0
  }
641
642
0
  cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
643
0
    enable ? CAP_SET : CAP_CLEAR);
644
645
  /* We never want to pass capabilities down to our children, so make
646
   * sure they are not inherited.
647
   */
648
0
  cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
649
650
0
  if (cap_set_proc(cap) == -1) {
651
0
    DBG_ERR("%s capability %d: cap_set_proc failed: %s\n",
652
0
      enable ? "adding" : "dropping",
653
0
      capability, strerror(errno));
654
0
    cap_free(cap);
655
0
    return False;
656
0
  }
657
0
  DBG_INFO("%s capability %d\n",
658
0
     enable ? "added" : "dropped", capability);
659
660
0
  cap_free(cap);
661
0
  return True;
662
0
}
663
664
#endif /* HAVE_POSIX_CAPABILITIES */
665
666
/****************************************************************************
667
 Gain the oplock capability from the kernel if possible.
668
****************************************************************************/
669
670
#if defined(HAVE_POSIX_CAPABILITIES) && defined(CAP_DAC_OVERRIDE)
671
static bool have_cap_dac_override = true;
672
#else
673
static bool have_cap_dac_override = false;
674
#endif
675
676
void set_effective_capability(enum smbd_capability capability)
677
0
{
678
0
  bool ret = false;
679
680
0
  if (capability != DAC_OVERRIDE_CAPABILITY || have_cap_dac_override) {
681
0
#if defined(HAVE_POSIX_CAPABILITIES)
682
0
    ret = set_process_capability(capability, True);
683
0
#endif /* HAVE_POSIX_CAPABILITIES */
684
0
  }
685
686
  /*
687
   * Fallback to become_root() if CAP_DAC_OVERRIDE is not
688
   * available.
689
   */
690
0
  if (capability == DAC_OVERRIDE_CAPABILITY) {
691
0
    if (!ret) {
692
0
      have_cap_dac_override = false;
693
0
    }
694
0
    if (!have_cap_dac_override) {
695
0
      become_root();
696
0
    }
697
0
  }
698
0
}
699
700
void drop_effective_capability(enum smbd_capability capability)
701
0
{
702
0
  if (capability != DAC_OVERRIDE_CAPABILITY || have_cap_dac_override) {
703
0
#if defined(HAVE_POSIX_CAPABILITIES)
704
0
    set_process_capability(capability, False);
705
0
#endif /* HAVE_POSIX_CAPABILITIES */
706
0
  } else {
707
0
    unbecome_root();
708
0
  }
709
0
}
710
711
/**************************************************************************
712
 Wrapper for random().
713
****************************************************************************/
714
715
long sys_random(void)
716
0
{
717
0
#if defined(HAVE_RANDOM)
718
0
  return (long)random();
719
#elif defined(HAVE_RAND)
720
  return (long)rand();
721
#else
722
  DEBUG(0,("Error - no random function available !\n"));
723
  exit(1);
724
#endif
725
0
}
726
727
/**************************************************************************
728
 Wrapper for srandom().
729
****************************************************************************/
730
731
void sys_srandom(unsigned int seed)
732
0
{
733
0
#if defined(HAVE_SRANDOM)
734
0
  srandom(seed);
735
#elif defined(HAVE_SRAND)
736
  srand(seed);
737
#else
738
  DEBUG(0,("Error - no srandom function available !\n"));
739
  exit(1);
740
#endif
741
0
}
742
743
#ifndef NGROUPS_MAX
744
#define NGROUPS_MAX 32 /* Guess... */
745
#endif
746
747
/**************************************************************************
748
 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
749
****************************************************************************/
750
751
int setgroups_max(void)
752
0
{
753
0
#if defined(SYSCONF_SC_NGROUPS_MAX)
754
0
  int ret = sysconf(_SC_NGROUPS_MAX);
755
0
  return (ret == -1) ? NGROUPS_MAX : ret;
756
#else
757
  return NGROUPS_MAX;
758
#endif
759
0
}
760
761
int getgroups_max(void)
762
0
{
763
#if defined(DARWINOS)
764
  /*
765
   * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group
766
   * nesting. However, The initgroups() manpage states the following:
767
   * "Note that OS X supports group membership in an unlimited number
768
   * of groups. The OS X kernel uses the group list stored in the process
769
   * credentials only as an initial cache.  Additional group memberships
770
   * are determined by communication between the operating system and the
771
   * opendirectoryd daemon."
772
   */
773
  return INT_MAX;
774
#else
775
0
  return setgroups_max();
776
0
#endif
777
0
}
778
779
/**************************************************************************
780
 Wrap setgroups and getgroups for systems that declare getgroups() as
781
 returning an array of gid_t, but actually return an array of int.
782
****************************************************************************/
783
784
#if defined(HAVE_BROKEN_GETGROUPS)
785
786
#ifdef HAVE_BROKEN_GETGROUPS
787
#define GID_T int
788
#else
789
#define GID_T gid_t
790
#endif
791
792
static int sys_broken_getgroups(int setlen, gid_t *gidset)
793
{
794
  GID_T *group_list;
795
  int i, ngroups;
796
797
  if(setlen == 0) {
798
    return getgroups(0, NULL);
799
  }
800
801
  /*
802
   * Broken case. We need to allocate a
803
   * GID_T array of size setlen.
804
   */
805
806
  if(setlen < 0) {
807
    errno = EINVAL;
808
    return -1;
809
  }
810
811
  if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
812
    DEBUG(0,("sys_getgroups: Malloc fail.\n"));
813
    return -1;
814
  }
815
816
  if((ngroups = getgroups(setlen, group_list)) < 0) {
817
    int saved_errno = errno;
818
    SAFE_FREE(group_list);
819
    errno = saved_errno;
820
    return -1;
821
  }
822
823
  /*
824
   * We're safe here as if ngroups > setlen then
825
   * getgroups *must* return EINVAL.
826
   * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
827
   */
828
829
  for(i = 0; i < ngroups; i++)
830
    gidset[i] = (gid_t)group_list[i];
831
832
  SAFE_FREE(group_list);
833
  return ngroups;
834
}
835
836
static int sys_broken_setgroups(int setlen, gid_t *gidset)
837
{
838
  GID_T *group_list;
839
  int i ;
840
841
  if (setlen == 0)
842
    return 0 ;
843
844
  if (setlen < 0 || setlen > setgroups_max()) {
845
    errno = EINVAL;
846
    return -1;
847
  }
848
849
  /*
850
   * Broken case. We need to allocate a
851
   * GID_T array of size setlen.
852
   */
853
854
  if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
855
    DEBUG(0,("sys_setgroups: Malloc fail.\n"));
856
    return -1;
857
  }
858
859
  for(i = 0; i < setlen; i++)
860
    group_list[i] = (GID_T) gidset[i];
861
862
  if(samba_setgroups(setlen, group_list) != 0) {
863
    int saved_errno = errno;
864
    SAFE_FREE(group_list);
865
    errno = saved_errno;
866
    return -1;
867
  }
868
869
  SAFE_FREE(group_list);
870
  return 0 ;
871
}
872
873
#endif /* HAVE_BROKEN_GETGROUPS */
874
875
/* This is a list of systems that require the first GID passed to setgroups(2)
876
 * to be the effective GID. If your system is one of these, add it here.
877
 */
878
#if defined (FREEBSD) || defined (DARWINOS)
879
#define USE_BSD_SETGROUPS
880
#endif
881
882
#if defined(USE_BSD_SETGROUPS)
883
/* Depending on the particular BSD implementation, the first GID that is
884
 * passed to setgroups(2) will either be ignored or will set the credential's
885
 * effective GID. In either case, the right thing to do is to guarantee that
886
 * gidset[0] is the effective GID.
887
 */
888
static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
889
{
890
  gid_t *new_gidset = NULL;
891
  int max;
892
  int ret;
893
894
  /* setgroups(2) will fail with EINVAL if we pass too many groups. */
895
  max = setgroups_max();
896
897
  /* No group list, just make sure we are setting the effective GID. */
898
  if (setlen == 0) {
899
    return samba_setgroups(1, &primary_gid);
900
  }
901
902
  /* If the primary gid is not the first array element, grow the array
903
   * and insert it at the front.
904
   */
905
  if (gidset[0] != primary_gid) {
906
          new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
907
          if (new_gidset == NULL) {
908
      return -1;
909
          }
910
911
    memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
912
    new_gidset[0] = primary_gid;
913
    setlen++;
914
  }
915
916
  if (setlen > max) {
917
    DEBUG(3, ("forced to truncate group list from %d to %d\n",
918
      setlen, max));
919
    setlen = max;
920
  }
921
922
#if defined(HAVE_BROKEN_GETGROUPS)
923
  ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
924
#else
925
  ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
926
#endif
927
928
  if (new_gidset) {
929
    int errsav = errno;
930
    SAFE_FREE(new_gidset);
931
    errno = errsav;
932
  }
933
934
  return ret;
935
}
936
937
#endif /* USE_BSD_SETGROUPS */
938
939
/**************************************************************************
940
 Wrapper for getgroups. Deals with broken (int) case.
941
****************************************************************************/
942
943
int sys_getgroups(int setlen, gid_t *gidset)
944
0
{
945
#if defined(HAVE_BROKEN_GETGROUPS)
946
  return sys_broken_getgroups(setlen, gidset);
947
#else
948
0
  return getgroups(setlen, gidset);
949
0
#endif
950
0
}
951
952
/**************************************************************************
953
 Wrapper for setgroups. Deals with broken (int) case and BSD case.
954
****************************************************************************/
955
956
int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
957
0
{
958
#if !defined(HAVE_SETGROUPS)
959
  errno = ENOSYS;
960
  return -1;
961
#endif /* HAVE_SETGROUPS */
962
963
#if defined(USE_BSD_SETGROUPS)
964
  return sys_bsd_setgroups(primary_gid, setlen, gidset);
965
#elif defined(HAVE_BROKEN_GETGROUPS)
966
  return sys_broken_setgroups(setlen, gidset);
967
#else
968
0
  return samba_setgroups(setlen, gidset);
969
0
#endif
970
0
}
971
972
/****************************************************************************
973
 Return the major devicenumber for UNIX extensions.
974
****************************************************************************/
975
976
uint32_t unix_dev_major(SMB_DEV_T dev)
977
0
{
978
0
#if defined(HAVE_DEVICE_MAJOR_FN)
979
0
        return (uint32_t)major(dev);
980
#else
981
        return (uint32_t)(dev >> 8);
982
#endif
983
0
}
984
985
/****************************************************************************
986
 Return the minor devicenumber for UNIX extensions.
987
****************************************************************************/
988
989
uint32_t unix_dev_minor(SMB_DEV_T dev)
990
0
{
991
0
#if defined(HAVE_DEVICE_MINOR_FN)
992
0
        return (uint32_t)minor(dev);
993
#else
994
        return (uint32_t)(dev & 0xff);
995
#endif
996
0
}
997
998
/**************************************************************************
999
 Wrapper for realpath.
1000
****************************************************************************/
1001
1002
char *sys_realpath(const char *path)
1003
0
{
1004
0
  char *result;
1005
1006
0
#ifdef REALPATH_TAKES_NULL
1007
0
  result = realpath(path, NULL);
1008
#else
1009
  result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
1010
  if (result) {
1011
    char *resolved_path = realpath(path, result);
1012
    if (!resolved_path) {
1013
      SAFE_FREE(result);
1014
    } else {
1015
      /* SMB_ASSERT(result == resolved_path) ? */
1016
      result = resolved_path;
1017
    }
1018
  }
1019
#endif
1020
0
  return result;
1021
0
}
1022
1023
bool sys_have_proc_fds(void)
1024
0
{
1025
0
  static bool checked = false;
1026
0
  static bool have_proc_fds = false;
1027
0
  struct stat sb;
1028
0
  int ret;
1029
1030
0
  if (checked) {
1031
0
    return have_proc_fds;
1032
0
  }
1033
1034
0
  ret = stat("/proc/self/fd/0", &sb);
1035
0
  have_proc_fds = (ret == 0);
1036
0
  checked = true;
1037
1038
0
  return have_proc_fds;
1039
0
}
1040
1041
char *sys_proc_fd_path(int fd, struct sys_proc_fd_path_buf *buf)
1042
0
{
1043
0
  int written =
1044
0
    snprintf(buf->buf, sizeof(buf->buf), "/proc/self/fd/%d", fd);
1045
1046
0
  SMB_ASSERT(sys_have_proc_fds() && (written >= 0));
1047
1048
0
  return buf->buf;
1049
0
}