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