LCOV - code coverage report
Current view: top level - source3/lib - system.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 194 229 84.7 %
Date: 2021-09-23 10:06:22 Functions: 32 38 84.2 %

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

Generated by: LCOV version 1.13