LCOV - code coverage report
Current view: top level - source3/lib - util_sec.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 88 116 75.9 %
Date: 2021-09-23 10:06:22 Functions: 16 20 80.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Copyright (C) Jeremy Allison 1998.
       4             :    rewritten for version 2.0.6 by Tridge
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #ifndef AUTOCONF_TEST
      21             : #include "includes.h"
      22             : #include "system/passwd.h" /* uid_wrapper */
      23             : #include "../lib/util/setid.h"
      24             : 
      25             : #else
      26             : /* we are running this code in autoconf test mode to see which type of setuid
      27             :    function works */
      28             : #if defined(HAVE_UNISTD_H)
      29             : #include <unistd.h>
      30             : #endif
      31             : #include <stdbool.h>
      32             : #include <stdlib.h>
      33             : #include <stdio.h>
      34             : #include <sys/types.h>
      35             : #include <errno.h>
      36             : 
      37             : #ifdef HAVE_SYS_PRIV_H
      38             : #include <sys/priv.h>
      39             : #endif
      40             : #ifdef HAVE_SYS_ID_H
      41             : #include <sys/id.h>
      42             : #endif
      43             : 
      44             : #define DEBUG(x, y) printf y
      45             : #define smb_panic(x) exit(1)
      46             : #endif
      47             : 
      48             : /* are we running as non-root? This is used by the regresison test code,
      49             :    and potentially also for sites that want non-root smbd */
      50             : static uid_t initial_uid;
      51             : static gid_t initial_gid;
      52             : 
      53             : /****************************************************************************
      54             : remember what uid we got started as - this allows us to run correctly
      55             : as non-root while catching trapdoor systems
      56             : ****************************************************************************/
      57             : 
      58        7807 : void sec_init(void)
      59             : {
      60             :         static int initialized;
      61             : 
      62        7807 :         if (!initialized) {
      63             : 
      64             : #ifndef AUTOCONF_TEST
      65        4298 :                 if (uid_wrapper_enabled()) {
      66        4298 :                         setenv("UID_WRAPPER_MYUID", "1", 1);
      67             :                 }
      68             : #endif
      69             : 
      70        4298 :                 initial_uid = geteuid();
      71        4298 :                 initial_gid = getegid();
      72             : 
      73             : #ifndef AUTOCONF_TEST
      74        4298 :                 if (uid_wrapper_enabled()) {
      75        4298 :                         unsetenv("UID_WRAPPER_MYUID");
      76             :                 }
      77             : #endif
      78             : 
      79        4298 :                 initialized = 1;
      80             :         }
      81        7807 : }
      82             : 
      83             : /****************************************************************************
      84             : some code (eg. winbindd) needs to know what uid we started as
      85             : ****************************************************************************/
      86       35968 : uid_t sec_initial_uid(void)
      87             : {
      88       35968 :         return initial_uid;
      89             : }
      90             : 
      91             : /****************************************************************************
      92             : some code (eg. winbindd, profiling shm) needs to know what gid we started as
      93             : ****************************************************************************/
      94         185 : gid_t sec_initial_gid(void)
      95             : {
      96         185 :         return initial_gid;
      97             : }
      98             : 
      99             : /**
     100             :  * @brief Check if we are running in root mode.
     101             :  *
     102             :  * @return Return whether Samba has root privileges
     103             :  */
     104      410199 : bool root_mode(void)
     105             : {
     106             :         uid_t euid;
     107             : 
     108      410199 :         euid = geteuid();
     109             : 
     110             : #ifndef AUTOCONF_TEST
     111      410199 :         if (uid_wrapper_enabled()) {
     112      410199 :                 return (euid == initial_uid || euid == (uid_t)0);
     113             :         }
     114             : #endif
     115             : 
     116           0 :         return (initial_uid == euid);
     117             : }
     118             : 
     119             : /****************************************************************************
     120             : are we running in non-root mode?
     121             : ****************************************************************************/
     122    11010478 : bool non_root_mode(void)
     123             : {
     124    11010478 :         return (initial_uid != (uid_t)0);
     125             : }
     126             : 
     127             : /****************************************************************************
     128             : abort if we haven't set the uid correctly
     129             : ****************************************************************************/
     130    11006775 : static void assert_uid(uid_t ruid, uid_t euid)
     131             : {
     132    11006775 :         if ((euid != (uid_t)-1 && geteuid() != euid) ||
     133        7759 :             (ruid != (uid_t)-1 && getuid() != ruid)) {
     134           7 :                 if (!non_root_mode()) {
     135           0 :                         DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
     136             :                                  (int)ruid, (int)euid,
     137             :                                  (int)getuid(), (int)geteuid()));
     138           0 :                         smb_panic("failed to set uid\n");
     139             :                         exit(1);
     140             :                 }
     141             :         }
     142    11006775 : }
     143             : 
     144             : /****************************************************************************
     145             : abort if we haven't set the gid correctly
     146             : ****************************************************************************/
     147    11006901 : static void assert_gid(gid_t rgid, gid_t egid)
     148             : {
     149    11006901 :         if ((egid != (gid_t)-1 && getegid() != egid) ||
     150        7822 :             (rgid != (gid_t)-1 && getgid() != rgid)) {
     151           7 :                 if (!non_root_mode()) {
     152           0 :                         DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
     153             :                                  (int)rgid, (int)egid,
     154             :                                  (int)getgid(), (int)getegid(),
     155             :                                  (int)getuid(), (int)geteuid()));
     156           0 :                         smb_panic("failed to set gid\n");
     157             :                         exit(1);
     158             :                 }
     159             :         }
     160    11006901 : }
     161             : 
     162             : /****************************************************************************
     163             :  Gain root privilege before doing something. 
     164             :  We want to end up with ruid==euid==0
     165             : ****************************************************************************/
     166        3911 : void gain_root_privilege(void)
     167             : {       
     168             : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
     169        3911 :         samba_setresuid(0,0,0);
     170             : #endif
     171             :     
     172             : #if USE_SETEUID
     173             :         samba_seteuid(0);
     174             : #endif
     175             : 
     176             : #if USE_SETREUID
     177             :         samba_setreuid(0, 0);
     178             : #endif
     179             : 
     180             : #if USE_SETUIDX
     181             :         samba_setuidx(ID_EFFECTIVE, 0);
     182             :         samba_setuidx(ID_REAL, 0);
     183             : #endif
     184             : 
     185             :         /* this is needed on some systems */
     186        3911 :         samba_setuid(0);
     187             : 
     188        3911 :         assert_uid(0, 0);
     189        3911 : }
     190             : 
     191             : 
     192             : /****************************************************************************
     193             :  Ensure our real and effective groups are zero.
     194             :  we want to end up with rgid==egid==0
     195             : ****************************************************************************/
     196        3911 : void gain_root_group_privilege(void)
     197             : {
     198             : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
     199        3911 :         samba_setresgid(0,0,0);
     200             : #endif
     201             : 
     202             : #if USE_SETREUID
     203             :         samba_setregid(0,0);
     204             : #endif
     205             : 
     206             : #if USE_SETEUID
     207             :         samba_setegid(0);
     208             : #endif
     209             : 
     210             : #if USE_SETUIDX
     211             :         samba_setgidx(ID_EFFECTIVE, 0);
     212             :         samba_setgidx(ID_REAL, 0);
     213             : #endif
     214             : 
     215        3911 :         samba_setgid(0);
     216             : 
     217        3911 :         assert_gid(0, 0);
     218        3911 : }
     219             : 
     220             : 
     221             : /****************************************************************************
     222             :  Set effective uid, and possibly the real uid too.
     223             :  We want to end up with either:
     224             :   
     225             :    ruid==uid and euid==uid
     226             : 
     227             :  or
     228             : 
     229             :    ruid==0 and euid==uid
     230             : 
     231             :  depending on what the local OS will allow us to regain root from.
     232             : ****************************************************************************/
     233    10999016 : void set_effective_uid(uid_t uid)
     234             : {
     235             : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
     236             :         /* Set the effective as well as the real uid. */
     237    10999016 :         if (samba_setresuid(uid,uid,-1) == -1) {
     238           7 :                 if (errno == EAGAIN) {
     239           0 :                         DEBUG(0, ("samba_setresuid failed with EAGAIN. uid(%d) "
     240             :                                   "might be over its NPROC limit\n",
     241             :                                   (int)uid));
     242             :                 }
     243             :         }
     244             : #endif
     245             : 
     246             : #if USE_SETREUID
     247             :         samba_setreuid(-1,uid);
     248             : #endif
     249             : 
     250             : #if USE_SETEUID
     251             :         samba_seteuid(uid);
     252             : #endif
     253             : 
     254             : #if USE_SETUIDX
     255             :         samba_setuidx(ID_EFFECTIVE, uid);
     256             : #endif
     257             : 
     258    10999016 :         assert_uid(-1, uid);
     259    10999016 : }
     260             : 
     261             : /****************************************************************************
     262             :  Set *only* the effective gid.
     263             :  we want to end up with rgid==0 and egid==gid
     264             : ****************************************************************************/
     265    10999079 : void set_effective_gid(gid_t gid)
     266             : {
     267             : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
     268    10999079 :         samba_setresgid(-1,gid,-1);
     269             : #endif
     270             : 
     271             : #if USE_SETREUID
     272             :         samba_setregid(-1,gid);
     273             : #endif
     274             : 
     275             : #if USE_SETEUID
     276             :         samba_setegid(gid);
     277             : #endif
     278             : 
     279             : #if USE_SETUIDX
     280             :         samba_setgidx(ID_EFFECTIVE, gid);
     281             : #endif
     282             : 
     283    10999079 :         assert_gid(-1, gid);
     284    10999079 : }
     285             : 
     286             : static uid_t saved_euid, saved_ruid;
     287             : static gid_t saved_egid, saved_rgid;
     288             : 
     289             : /****************************************************************************
     290             :  save the real and effective uid for later restoration. Used by the quotas
     291             :  code
     292             : ****************************************************************************/
     293           0 : void save_re_uid(void)
     294             : {
     295           0 :         saved_ruid = getuid();
     296           0 :         saved_euid = geteuid();
     297           0 : }
     298             : 
     299             : 
     300             : /****************************************************************************
     301             :  and restore them!
     302             : ****************************************************************************/
     303             : 
     304           0 : void restore_re_uid_fromroot(void)
     305             : {
     306             : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
     307           0 :         samba_setresuid(saved_ruid, saved_euid, -1);
     308             : #elif USE_SETREUID
     309             :         samba_setreuid(saved_ruid, -1);
     310             :         samba_setreuid(-1,saved_euid);
     311             : #elif USE_SETUIDX
     312             :         samba_setuidx(ID_REAL, saved_ruid);
     313             :         samba_setuidx(ID_EFFECTIVE, saved_euid);
     314             : #else
     315             :         set_effective_uid(saved_euid);
     316             :         if (getuid() != saved_ruid)
     317             :                 samba_setuid(saved_ruid);
     318             :         set_effective_uid(saved_euid);
     319             : #endif
     320             : 
     321           0 :         assert_uid(saved_ruid, saved_euid);
     322           0 : }
     323             : 
     324           0 : void restore_re_uid(void)
     325             : {
     326           0 :         set_effective_uid(0);
     327           0 :         restore_re_uid_fromroot();
     328           0 : }
     329             : 
     330             : /****************************************************************************
     331             :  save the real and effective gid for later restoration. Used by the 
     332             :  getgroups code
     333             : ****************************************************************************/
     334          63 : void save_re_gid(void)
     335             : {
     336          63 :         saved_rgid = getgid();
     337          63 :         saved_egid = getegid();
     338          63 : }
     339             : 
     340             : /****************************************************************************
     341             :  and restore them!
     342             : ****************************************************************************/
     343          63 : void restore_re_gid(void)
     344             : {
     345             : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
     346          63 :         samba_setresgid(saved_rgid, saved_egid, -1);
     347             : #elif USE_SETREUID
     348             :         samba_setregid(saved_rgid, -1);
     349             :         samba_setregid(-1,saved_egid);
     350             : #elif USE_SETUIDX
     351             :         samba_setgidx(ID_REAL, saved_rgid);
     352             :         samba_setgidx(ID_EFFECTIVE, saved_egid);
     353             : #else
     354             :         set_effective_gid(saved_egid);
     355             :         if (getgid() != saved_rgid)
     356             :                 samba_setgid(saved_rgid);
     357             :         set_effective_gid(saved_egid);
     358             : #endif
     359             : 
     360          63 :         assert_gid(saved_rgid, saved_egid);
     361          63 : }
     362             : 
     363             : 
     364             : /****************************************************************************
     365             :  set the real AND effective uid to the current effective uid in a way that
     366             :  allows root to be regained.
     367             :  This is only possible on some platforms.
     368             : ****************************************************************************/
     369           0 : int set_re_uid(void)
     370             : {
     371           0 :         uid_t uid = geteuid();
     372             : 
     373             : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
     374           0 :         samba_setresuid(uid, uid, -1);
     375             : #endif
     376             : 
     377             : #if USE_SETREUID
     378             :         samba_setreuid(0, 0);
     379             :         samba_setreuid(uid, -1);
     380             :         samba_setreuid(-1, uid);
     381             : #endif
     382             : 
     383             : #if USE_SETEUID
     384             :         /* can't be done */
     385             :         return -1;
     386             : #endif
     387             : 
     388             : #if USE_SETUIDX
     389             :         /* can't be done */
     390             :         return -1;
     391             : #endif
     392             : 
     393           0 :         assert_uid(uid, uid);
     394           0 :         return 0;
     395             : }
     396             : 
     397             : 
     398             : /****************************************************************************
     399             :  Become the specified uid and gid - permanently !
     400             :  there should be no way back if possible
     401             : ****************************************************************************/
     402        3848 : void become_user_permanently(uid_t uid, gid_t gid)
     403             : {
     404             :         /*
     405             :          * First - gain root privilege. We do this to ensure
     406             :          * we can lose it again.
     407             :          */
     408             : 
     409        3848 :         gain_root_privilege();
     410        3848 :         gain_root_group_privilege();
     411             : 
     412             : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
     413        3848 :         samba_setresgid(gid,gid,gid);
     414        3848 :         samba_setgid(gid);
     415        3848 :         samba_setresuid(uid,uid,uid);
     416        3848 :         samba_setuid(uid);
     417             : #endif
     418             : 
     419             : #if USE_SETREUID
     420             :         samba_setregid(gid,gid);
     421             :         samba_setgid(gid);
     422             :         samba_setreuid(uid,uid);
     423             :         samba_setuid(uid);
     424             : #endif
     425             : 
     426             : #if USE_SETEUID
     427             :         samba_setegid(gid);
     428             :         samba_setgid(gid);
     429             :         samba_setuid(uid);
     430             :         samba_seteuid(uid);
     431             :         samba_setuid(uid);
     432             : #endif
     433             : 
     434             : #if USE_SETUIDX
     435             :         samba_setgidx(ID_REAL, gid);
     436             :         samba_setgidx(ID_EFFECTIVE, gid);
     437             :         samba_setgid(gid);
     438             :         samba_setuidx(ID_REAL, uid);
     439             :         samba_setuidx(ID_EFFECTIVE, uid);
     440             :         samba_setuid(uid);
     441             : #endif
     442             :         
     443        3848 :         assert_uid(uid, uid);
     444        3848 :         assert_gid(gid, gid);
     445        3848 : }
     446             : 
     447             : #if defined(HAVE_LINUX_THREAD_CREDENTIALS) && defined(HAVE___THREAD)
     448             :         struct set_thread_credentials_cache {
     449             :                 bool active;
     450             :                 uid_t uid;
     451             :                 gid_t gid;
     452             :                 size_t setlen;
     453             :                 uintptr_t gidset;
     454             :         };
     455             : static __thread struct set_thread_credentials_cache cache;
     456             : #endif
     457             : 
     458             : /**********************************************************
     459             :  Function to set thread specific credentials. Leave
     460             :  saved-set uid/gid alone.Must be thread-safe code.
     461             : **********************************************************/
     462             : 
     463       20118 : int set_thread_credentials(uid_t uid,
     464             :                         gid_t gid,
     465             :                         size_t setlen,
     466             :                         const gid_t *gidset)
     467             : {
     468             : #if defined(HAVE_LINUX_THREAD_CREDENTIALS)
     469             :         /*
     470             :          * With Linux thread-specific credentials
     471             :          * we know we have setresuid/setresgid
     472             :          * available.
     473             :          */
     474             : #ifdef HAVE___THREAD
     475       40209 :         if (cache.active &&
     476       40182 :             cache.uid == uid &&
     477       40182 :             cache.gid == gid &&
     478       40182 :             cache.setlen == setlen &&
     479       20091 :             (const gid_t *)cache.gidset == gidset)
     480             :         {
     481       20091 :                 return 0;
     482             :         }
     483             : #endif /* HAVE___THREAD */
     484             : 
     485             :         /* Become root. */
     486             :         /* Set ru=0, eu=0 */
     487          27 :         if (samba_setresuid(0, 0, -1) != 0) {
     488           0 :                 return -1;
     489             :         }
     490             :         /* Set our primary gid. */
     491             :         /* Set rg=gid, eg=gid */
     492          27 :         if (samba_setresgid(gid, gid, -1) != 0) {
     493           0 :                 return -1;
     494             :         }
     495             :         /* Set extra groups list. */
     496          27 :         if (samba_setgroups(setlen, gidset) != 0) {
     497           0 :                 return -1;
     498             :         }
     499             :         /* Become the requested user. */
     500             :         /* Set ru=uid, eu=uid */
     501          27 :         if (samba_setresuid(uid, uid, -1) != 0) {
     502           0 :                 return -1;
     503             :         }
     504          54 :         if (geteuid() != uid || getuid() != uid ||
     505          54 :                         getegid() != gid || getgid() != gid) {
     506           0 :                 smb_panic("set_thread_credentials failed\n");
     507             :                 return -1;
     508             :         }
     509             : 
     510             : #ifdef HAVE___THREAD
     511          27 :         cache.active = true;
     512          27 :         cache.uid = uid;
     513          27 :         cache.gid = gid;
     514          27 :         cache.setlen = setlen;
     515          27 :         cache.gidset = (uintptr_t)gidset;
     516             : #endif /* HAVE___THREAD */
     517             : 
     518          27 :         return 0;
     519             : #else
     520             :         errno = ENOSYS;
     521             :         return -1;
     522             : #endif
     523             : }
     524             : 
     525             : #ifdef AUTOCONF_TEST
     526             : 
     527             : /****************************************************************************
     528             : this function just checks that we don't get ENOSYS back
     529             : ****************************************************************************/
     530             : static int have_syscall(void)
     531             : {
     532             :         errno = 0;
     533             : 
     534             : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
     535             :         samba_setresuid(-1,-1,-1);
     536             : #endif
     537             : 
     538             : #if USE_SETREUID
     539             :         samba_setreuid(-1,-1);
     540             : #endif
     541             : 
     542             : #if USE_SETEUID
     543             :         samba_seteuid(-1);
     544             : #endif
     545             : 
     546             : #if USE_SETUIDX
     547             :         samba_setuidx(ID_EFFECTIVE, -1);
     548             : #endif
     549             : 
     550             :         if (errno == ENOSYS) {
     551             :                 return -1;
     552             :         }
     553             :         return 0;
     554             : }
     555             : 
     556             : int main(void)
     557             : {
     558             :         if (getuid() != 0) {
     559             : #if (defined(AIX) && defined(USE_SETREUID))
     560             :                 /* setreuid is badly broken on AIX 4.1, we avoid it completely */
     561             :                 fprintf(stderr,"avoiding possibly broken setreuid\n");
     562             :                 exit(1);
     563             : #endif
     564             : 
     565             :                 /* if not running as root then at least check to see if we get ENOSYS - this 
     566             :                    handles Linux 2.0.x with glibc 2.1 */
     567             :                 fprintf(stderr,"not running as root: checking for ENOSYS\n");
     568             :                 exit(have_syscall());
     569             :         }
     570             : 
     571             :         gain_root_privilege();
     572             :         gain_root_group_privilege();
     573             :         set_effective_gid(1);
     574             :         set_effective_uid(1);
     575             :         save_re_uid();
     576             :         restore_re_uid();
     577             :         gain_root_privilege();
     578             :         gain_root_group_privilege();
     579             :         become_user_permanently(1, 1);
     580             :         samba_setuid(0);
     581             :         if (getuid() == 0) {
     582             :                 fprintf(stderr,"uid not set permanently\n");
     583             :                 exit(1);
     584             :         }
     585             : 
     586             :         printf("OK\n");
     587             : 
     588             :         exit(0);
     589             : }
     590             : #endif
     591             : 
     592             : /****************************************************************************
     593             : Check if we are setuid root.  Used in libsmb and smbpasswd paranoia checks.
     594             : ****************************************************************************/
     595       15295 : bool is_setuid_root(void) 
     596             : {
     597       15295 :         return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
     598             : }

Generated by: LCOV version 1.13