root/source3/lib/util_sec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sec_init
  2. sec_initial_uid
  3. sec_initial_gid
  4. non_root_mode
  5. assert_uid
  6. assert_gid
  7. gain_root_privilege
  8. gain_root_group_privilege
  9. set_effective_uid
  10. set_effective_gid
  11. save_re_uid
  12. restore_re_uid_fromroot
  13. restore_re_uid
  14. save_re_gid
  15. restore_re_gid
  16. set_re_uid
  17. become_user_permanently
  18. have_syscall
  19. main
  20. is_setuid_root

   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 #else
  23 /* we are running this code in autoconf test mode to see which type of setuid
  24    function works */
  25 #if defined(HAVE_UNISTD_H)
  26 #include <unistd.h>
  27 #endif
  28 #include <stdlib.h>
  29 #include <stdio.h>
  30 #include <sys/types.h>
  31 #include <errno.h>
  32 
  33 #ifdef HAVE_SYS_PRIV_H
  34 #include <sys/priv.h>
  35 #endif
  36 #ifdef HAVE_SYS_ID_H
  37 #include <sys/id.h>
  38 #endif
  39 
  40 #define DEBUG(x, y) printf y
  41 #define smb_panic(x) exit(1)
  42 #define bool int
  43 #endif
  44 
  45 /* are we running as non-root? This is used by the regresison test code,
  46    and potentially also for sites that want non-root smbd */
  47 static uid_t initial_uid;
  48 static gid_t initial_gid;
  49 
  50 /****************************************************************************
  51 remember what uid we got started as - this allows us to run correctly
  52 as non-root while catching trapdoor systems
  53 ****************************************************************************/
  54 
  55 void sec_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
  56 {
  57         static int initialized;
  58 
  59         if (!initialized) {
  60                 initial_uid = geteuid();
  61                 initial_gid = getegid();
  62                 initialized = 1;
  63         }
  64 }
  65 
  66 /****************************************************************************
  67 some code (eg. winbindd) needs to know what uid we started as
  68 ****************************************************************************/
  69 uid_t sec_initial_uid(void)
     /* [<][>][^][v][top][bottom][index][help] */
  70 {
  71         return initial_uid;
  72 }
  73 
  74 /****************************************************************************
  75 some code (eg. winbindd, profiling shm) needs to know what gid we started as
  76 ****************************************************************************/
  77 gid_t sec_initial_gid(void)
     /* [<][>][^][v][top][bottom][index][help] */
  78 {
  79         return initial_gid;
  80 }
  81 
  82 /****************************************************************************
  83 are we running in non-root mode?
  84 ****************************************************************************/
  85 bool non_root_mode(void)
     /* [<][>][^][v][top][bottom][index][help] */
  86 {
  87         return (initial_uid != (uid_t)0);
  88 }
  89 
  90 /****************************************************************************
  91 abort if we haven't set the uid correctly
  92 ****************************************************************************/
  93 static void assert_uid(uid_t ruid, uid_t euid)
     /* [<][>][^][v][top][bottom][index][help] */
  94 {
  95         if ((euid != (uid_t)-1 && geteuid() != euid) ||
  96             (ruid != (uid_t)-1 && getuid() != ruid)) {
  97                 if (!non_root_mode()) {
  98                         DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
  99                                  (int)ruid, (int)euid,
 100                                  (int)getuid(), (int)geteuid()));
 101                         smb_panic("failed to set uid\n");
 102                         exit(1);
 103                 }
 104         }
 105 }
 106 
 107 /****************************************************************************
 108 abort if we haven't set the gid correctly
 109 ****************************************************************************/
 110 static void assert_gid(gid_t rgid, gid_t egid)
     /* [<][>][^][v][top][bottom][index][help] */
 111 {
 112         if ((egid != (gid_t)-1 && getegid() != egid) ||
 113             (rgid != (gid_t)-1 && getgid() != rgid)) {
 114                 if (!non_root_mode()) {
 115                         DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
 116                                  (int)rgid, (int)egid,
 117                                  (int)getgid(), (int)getegid(),
 118                                  (int)getuid(), (int)geteuid()));
 119                         smb_panic("failed to set gid\n");
 120                         exit(1);
 121                 }
 122         }
 123 }
 124 
 125 /****************************************************************************
 126  Gain root privilege before doing something. 
 127  We want to end up with ruid==euid==0
 128 ****************************************************************************/
 129 void gain_root_privilege(void)
     /* [<][>][^][v][top][bottom][index][help] */
 130 {       
 131 #if USE_SETRESUID
 132         setresuid(0,0,0);
 133 #endif
 134     
 135 #if USE_SETEUID
 136         seteuid(0);
 137 #endif
 138 
 139 #if USE_SETREUID
 140         setreuid(0, 0);
 141 #endif
 142 
 143 #if USE_SETUIDX
 144         setuidx(ID_EFFECTIVE, 0);
 145         setuidx(ID_REAL, 0);
 146 #endif
 147 
 148         /* this is needed on some systems */
 149         setuid(0);
 150 
 151         assert_uid(0, 0);
 152 }
 153 
 154 
 155 /****************************************************************************
 156  Ensure our real and effective groups are zero.
 157  we want to end up with rgid==egid==0
 158 ****************************************************************************/
 159 void gain_root_group_privilege(void)
     /* [<][>][^][v][top][bottom][index][help] */
 160 {
 161 #if USE_SETRESUID
 162         setresgid(0,0,0);
 163 #endif
 164 
 165 #if USE_SETREUID
 166         setregid(0,0);
 167 #endif
 168 
 169 #if USE_SETEUID
 170         setegid(0);
 171 #endif
 172 
 173 #if USE_SETUIDX
 174         setgidx(ID_EFFECTIVE, 0);
 175         setgidx(ID_REAL, 0);
 176 #endif
 177 
 178         setgid(0);
 179 
 180         assert_gid(0, 0);
 181 }
 182 
 183 
 184 /****************************************************************************
 185  Set effective uid, and possibly the real uid too.
 186  We want to end up with either:
 187   
 188    ruid==uid and euid==uid
 189 
 190  or
 191 
 192    ruid==0 and euid==uid
 193 
 194  depending on what the local OS will allow us to regain root from.
 195 ****************************************************************************/
 196 void set_effective_uid(uid_t uid)
     /* [<][>][^][v][top][bottom][index][help] */
 197 {
 198 #if USE_SETRESUID
 199         /* Set the effective as well as the real uid. */
 200         if (setresuid(uid,uid,-1) == -1) {
 201                 if (errno == EAGAIN) {
 202                         DEBUG(0, ("setresuid failed with EAGAIN. uid(%d) "
 203                                   "might be over its NPROC limit\n",
 204                                   (int)uid));
 205                 }
 206         }
 207 #endif
 208 
 209 #if USE_SETREUID
 210         setreuid(-1,uid);
 211 #endif
 212 
 213 #if USE_SETEUID
 214         seteuid(uid);
 215 #endif
 216 
 217 #if USE_SETUIDX
 218         setuidx(ID_EFFECTIVE, uid);
 219 #endif
 220 
 221         assert_uid(-1, uid);
 222 }
 223 
 224 /****************************************************************************
 225  Set *only* the effective gid.
 226  we want to end up with rgid==0 and egid==gid
 227 ****************************************************************************/
 228 void set_effective_gid(gid_t gid)
     /* [<][>][^][v][top][bottom][index][help] */
 229 {
 230 #if USE_SETRESUID
 231         setresgid(-1,gid,-1);
 232 #endif
 233 
 234 #if USE_SETREUID
 235         setregid(-1,gid);
 236 #endif
 237 
 238 #if USE_SETEUID
 239         setegid(gid);
 240 #endif
 241 
 242 #if USE_SETUIDX
 243         setgidx(ID_EFFECTIVE, gid);
 244 #endif
 245 
 246         assert_gid(-1, gid);
 247 }
 248 
 249 static uid_t saved_euid, saved_ruid;
 250 static gid_t saved_egid, saved_rgid;
 251 
 252 /****************************************************************************
 253  save the real and effective uid for later restoration. Used by the quotas
 254  code
 255 ****************************************************************************/
 256 void save_re_uid(void)
     /* [<][>][^][v][top][bottom][index][help] */
 257 {
 258         saved_ruid = getuid();
 259         saved_euid = geteuid();
 260 }
 261 
 262 
 263 /****************************************************************************
 264  and restore them!
 265 ****************************************************************************/
 266 
 267 void restore_re_uid_fromroot(void)
     /* [<][>][^][v][top][bottom][index][help] */
 268 {
 269 #if USE_SETRESUID
 270         setresuid(saved_ruid, saved_euid, -1);
 271 #elif USE_SETREUID
 272         setreuid(saved_ruid, -1);
 273         setreuid(-1,saved_euid);
 274 #elif USE_SETUIDX
 275         setuidx(ID_REAL, saved_ruid);
 276         setuidx(ID_EFFECTIVE, saved_euid);
 277 #else
 278         set_effective_uid(saved_euid);
 279         if (getuid() != saved_ruid)
 280                 setuid(saved_ruid);
 281         set_effective_uid(saved_euid);
 282 #endif
 283 
 284         assert_uid(saved_ruid, saved_euid);
 285 }
 286 
 287 void restore_re_uid(void)
     /* [<][>][^][v][top][bottom][index][help] */
 288 {
 289         set_effective_uid(0);
 290         restore_re_uid_fromroot();
 291 }
 292 
 293 /****************************************************************************
 294  save the real and effective gid for later restoration. Used by the 
 295  getgroups code
 296 ****************************************************************************/
 297 void save_re_gid(void)
     /* [<][>][^][v][top][bottom][index][help] */
 298 {
 299         saved_rgid = getgid();
 300         saved_egid = getegid();
 301 }
 302 
 303 /****************************************************************************
 304  and restore them!
 305 ****************************************************************************/
 306 void restore_re_gid(void)
     /* [<][>][^][v][top][bottom][index][help] */
 307 {
 308 #if USE_SETRESUID
 309         setresgid(saved_rgid, saved_egid, -1);
 310 #elif USE_SETREUID
 311         setregid(saved_rgid, -1);
 312         setregid(-1,saved_egid);
 313 #elif USE_SETUIDX
 314         setgidx(ID_REAL, saved_rgid);
 315         setgidx(ID_EFFECTIVE, saved_egid);
 316 #else
 317         set_effective_gid(saved_egid);
 318         if (getgid() != saved_rgid)
 319                 setgid(saved_rgid);
 320         set_effective_gid(saved_egid);
 321 #endif
 322 
 323         assert_gid(saved_rgid, saved_egid);
 324 }
 325 
 326 
 327 /****************************************************************************
 328  set the real AND effective uid to the current effective uid in a way that
 329  allows root to be regained.
 330  This is only possible on some platforms.
 331 ****************************************************************************/
 332 int set_re_uid(void)
     /* [<][>][^][v][top][bottom][index][help] */
 333 {
 334         uid_t uid = geteuid();
 335 
 336 #if USE_SETRESUID
 337         setresuid(geteuid(), -1, -1);
 338 #endif
 339 
 340 #if USE_SETREUID
 341         setreuid(0, 0);
 342         setreuid(uid, -1);
 343         setreuid(-1, uid);
 344 #endif
 345 
 346 #if USE_SETEUID
 347         /* can't be done */
 348         return -1;
 349 #endif
 350 
 351 #if USE_SETUIDX
 352         /* can't be done */
 353         return -1;
 354 #endif
 355 
 356         assert_uid(uid, uid);
 357         return 0;
 358 }
 359 
 360 
 361 /****************************************************************************
 362  Become the specified uid and gid - permanently !
 363  there should be no way back if possible
 364 ****************************************************************************/
 365 void become_user_permanently(uid_t uid, gid_t gid)
     /* [<][>][^][v][top][bottom][index][help] */
 366 {
 367         /*
 368          * First - gain root privilege. We do this to ensure
 369          * we can lose it again.
 370          */
 371 
 372         gain_root_privilege();
 373         gain_root_group_privilege();
 374 
 375 #if USE_SETRESUID
 376         setresgid(gid,gid,gid);
 377         setgid(gid);
 378         setresuid(uid,uid,uid);
 379         setuid(uid);
 380 #endif
 381 
 382 #if USE_SETREUID
 383         setregid(gid,gid);
 384         setgid(gid);
 385         setreuid(uid,uid);
 386         setuid(uid);
 387 #endif
 388 
 389 #if USE_SETEUID
 390         setegid(gid);
 391         setgid(gid);
 392         setuid(uid);
 393         seteuid(uid);
 394         setuid(uid);
 395 #endif
 396 
 397 #if USE_SETUIDX
 398         setgidx(ID_REAL, gid);
 399         setgidx(ID_EFFECTIVE, gid);
 400         setgid(gid);
 401         setuidx(ID_REAL, uid);
 402         setuidx(ID_EFFECTIVE, uid);
 403         setuid(uid);
 404 #endif
 405         
 406         assert_uid(uid, uid);
 407         assert_gid(gid, gid);
 408 }
 409 
 410 #ifdef AUTOCONF_TEST
 411 
 412 /****************************************************************************
 413 this function just checks that we don't get ENOSYS back
 414 ****************************************************************************/
 415 static int have_syscall(void)
     /* [<][>][^][v][top][bottom][index][help] */
 416 {
 417         errno = 0;
 418 
 419 #if USE_SETRESUID
 420         setresuid(-1,-1,-1);
 421 #endif
 422 
 423 #if USE_SETREUID
 424         setreuid(-1,-1);
 425 #endif
 426 
 427 #if USE_SETEUID
 428         seteuid(-1);
 429 #endif
 430 
 431 #if USE_SETUIDX
 432         setuidx(ID_EFFECTIVE, -1);
 433 #endif
 434 
 435         if (errno == ENOSYS) return -1;
 436         
 437         return 0;
 438 }
 439 
 440 main()
     /* [<][>][^][v][top][bottom][index][help] */
 441 {
 442         if (getuid() != 0) {
 443 #if (defined(AIX) && defined(USE_SETREUID))
 444                 /* setreuid is badly broken on AIX 4.1, we avoid it completely */
 445                 fprintf(stderr,"avoiding possibly broken setreuid\n");
 446                 exit(1);
 447 #endif
 448 
 449                 /* if not running as root then at least check to see if we get ENOSYS - this 
 450                    handles Linux 2.0.x with glibc 2.1 */
 451                 fprintf(stderr,"not running as root: checking for ENOSYS\n");
 452                 exit(have_syscall());
 453         }
 454 
 455         gain_root_privilege();
 456         gain_root_group_privilege();
 457         set_effective_gid(1);
 458         set_effective_uid(1);
 459         save_re_uid();
 460         restore_re_uid();
 461         gain_root_privilege();
 462         gain_root_group_privilege();
 463         become_user_permanently(1, 1);
 464         setuid(0);
 465         if (getuid() == 0) {
 466                 fprintf(stderr,"uid not set permanently\n");
 467                 exit(1);
 468         }
 469 
 470         printf("OK\n");
 471 
 472         exit(0);
 473 }
 474 #endif
 475 
 476 /****************************************************************************
 477 Check if we are setuid root.  Used in libsmb and smbpasswd paranoia checks.
 478 ****************************************************************************/
 479 bool is_setuid_root(void) 
     /* [<][>][^][v][top][bottom][index][help] */
 480 {
 481         return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
 482 }

/* [<][>][^][v][top][bottom][index][help] */