LCOV - code coverage report
Current view: top level - source3/lib - system.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 157 211 74.4 %
Date: 2024-06-13 04:01:37 Functions: 27 36 75.0 %

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

Generated by: LCOV version 1.13