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

Generated by: LCOV version 1.14