LCOV - code coverage report
Current view: top level - source3/lib - system.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 206 249 82.7 %
Date: 2024-05-31 13:13:24 Functions: 32 37 86.5 %

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

Generated by: LCOV version 1.14