1/* 2 Unix SMB/Netbios implementation. 3 Version 2.0 4 Copyright (C) Jeremy Allison 1998. 5 rewritten for version 2.0.6 by Tridge 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*/ 21 22#ifndef AUTOCONF_TEST 23#include "includes.h" 24extern int DEBUGLEVEL; 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 <stdlib.h> 32#include <stdio.h> 33#include <sys/types.h> 34#include <errno.h> 35 36#ifdef HAVE_SYS_PRIV_H 37#include <sys/priv.h> 38#endif 39#ifdef HAVE_SYS_ID_H 40#include <sys/id.h> 41#endif 42 43#define DEBUG(x, y) printf y 44#define smb_panic(x) exit(1) 45#endif 46 47/**************************************************************************** 48abort if we haven't set the uid correctly 49****************************************************************************/ 50static void assert_uid(uid_t ruid, uid_t euid) 51{ 52 if ((euid != (uid_t)-1 && geteuid() != euid) || 53 (ruid != (uid_t)-1 && getuid() != ruid)) { 54 DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n", 55 (int)ruid, (int)euid, 56 (int)getuid(), (int)geteuid())); 57 smb_panic("failed to set uid\n"); 58 exit(1); 59 } 60} 61 62/**************************************************************************** 63abort if we haven't set the gid correctly 64****************************************************************************/ 65static void assert_gid(gid_t rgid, gid_t egid) 66{ 67 if ((egid != (gid_t)-1 && getegid() != egid) || 68 (rgid != (gid_t)-1 && getgid() != rgid)) { 69 DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n", 70 (int)rgid, (int)egid, 71 (int)getgid(), (int)getegid(), 72 (int)getuid(), (int)geteuid())); 73 smb_panic("failed to set gid\n"); 74 exit(1); 75 } 76} 77 78/**************************************************************************** 79 Gain root privilege before doing something. 80 We want to end up with ruid==euid==0 81****************************************************************************/ 82void gain_root_privilege(void) 83{ 84#if USE_SETRESUID 85 setresuid(0,0,0); 86#endif 87 88#if USE_SETEUID 89 seteuid(0); 90#endif 91 92#if USE_SETREUID 93 setreuid(0, 0); 94#endif 95 96#if USE_SETUIDX 97 setuidx(ID_EFFECTIVE, 0); 98 setuidx(ID_REAL, 0); 99#endif 100 101 /* this is needed on some systems */ 102 setuid(0); 103 104 assert_uid(0, 0); 105} 106 107 108/**************************************************************************** 109 Ensure our real and effective groups are zero. 110 we want to end up with rgid==egid==0 111****************************************************************************/ 112void gain_root_group_privilege(void) 113{ 114#if USE_SETRESUID 115 setresgid(0,0,0); 116#endif 117 118#if USE_SETREUID 119 setregid(0,0); 120#endif 121 122#if USE_SETEUID 123 setegid(0); 124#endif 125 126#if USE_SETUIDX 127 setgidx(ID_EFFECTIVE, 0); 128 setgidx(ID_REAL, 0); 129#endif 130 131 setgid(0); 132 133 assert_gid(0, 0); 134} 135 136 137/**************************************************************************** 138 Set *only* the effective uid. 139 we want to end up with ruid==0 and euid==uid 140****************************************************************************/ 141void set_effective_uid(uid_t uid) 142{ 143#if USE_SETRESUID 144 setresuid(-1,uid,-1); 145#endif 146 147#if USE_SETREUID 148 setreuid(-1,uid); 149#endif 150 151#if USE_SETEUID 152 seteuid(uid); 153#endif 154 155#if USE_SETUIDX 156 setuidx(ID_EFFECTIVE, uid); 157#endif 158 159 assert_uid(-1, uid); 160} 161 162/**************************************************************************** 163 Set *only* the effective gid. 164 we want to end up with rgid==0 and egid==gid 165****************************************************************************/ 166void set_effective_gid(gid_t gid) 167{ 168#if USE_SETRESUID 169 setresgid(-1,gid,-1); 170#endif 171 172#if USE_SETREUID 173 setregid(-1,gid); 174#endif 175 176#if USE_SETEUID 177 setegid(gid); 178#endif 179 180#if USE_SETUIDX 181 setgidx(ID_EFFECTIVE, gid); 182#endif 183 184 assert_gid(-1, gid); 185} 186 187static uid_t saved_euid, saved_ruid; 188 189/**************************************************************************** 190 save the real and effective uid for later restoration. Used by the quotas 191 code 192****************************************************************************/ 193void save_re_uid(void) 194{ 195 saved_ruid = getuid(); 196 saved_euid = geteuid(); 197} 198 199 200/**************************************************************************** 201 and restore them! 202****************************************************************************/ 203void restore_re_uid(void) 204{ 205 set_effective_uid(0); 206 207#if USE_SETRESUID 208 setresuid(saved_ruid, saved_euid, -1); 209#elif USE_SETREUID 210 setreuid(saved_ruid, -1); 211 setreuid(-1,saved_euid); 212#elif USE_SETUIDX 213 setuidx(ID_REAL, saved_ruid); 214 setuidx(ID_EFFECTIVE, saved_euid); 215#else 216 set_effective_uid(saved_euid); 217 if (getuid() != saved_ruid) 218 setuid(saved_ruid); 219 set_effective_uid(saved_euid); 220#endif 221 222 assert_uid(saved_ruid, saved_euid); 223} 224 225/**************************************************************************** 226 set the real AND effective uid to the current effective uid in a way that 227 allows root to be regained. 228 This is only possible on some platforms. 229****************************************************************************/ 230int set_re_uid(void) 231{ 232 uid_t uid = geteuid(); 233 234#if USE_SETRESUID 235 setresuid(geteuid(), -1, -1); 236#endif 237 238#if USE_SETREUID 239 setreuid(0, 0); 240 setreuid(uid, -1); 241 setreuid(-1, uid); 242#endif 243 244#if USE_SETEUID 245 /* can't be done */ 246 return -1; 247#endif 248 249#if USE_SETUIDX 250 /* can't be done */ 251 return -1; 252#endif 253 254 assert_uid(uid, uid); 255 return 0; 256} 257 258 259/**************************************************************************** 260 Become the specified uid and gid - permanently ! 261 there should be no way back if possible 262****************************************************************************/ 263void become_user_permanently(uid_t uid, gid_t gid) 264{ 265 /* 266 * First - gain root privilege. We do this to ensure 267 * we can lose it again. 268 */ 269 270 gain_root_privilege(); 271 gain_root_group_privilege(); 272 273#if USE_SETRESUID 274 setresgid(gid,gid,gid); 275 setgid(gid); 276 setresuid(uid,uid,uid); 277 setuid(uid); 278#endif 279 280#if USE_SETREUID 281 setregid(gid,gid); 282 setgid(gid); 283 setreuid(uid,uid); 284 setuid(uid); 285#endif 286 287#if USE_SETEUID 288 setegid(gid); 289 setgid(gid); 290 setuid(uid); 291 seteuid(uid); 292 setuid(uid); 293#endif 294 295#if USE_SETUIDX 296 setgidx(ID_REAL, gid); 297 setgidx(ID_EFFECTIVE, gid); 298 setgid(gid); 299 setuidx(ID_REAL, uid); 300 setuidx(ID_EFFECTIVE, uid); 301 setuid(uid); 302#endif 303 304 assert_uid(uid, uid); 305 assert_gid(gid, gid); 306} 307 308 309/**************************************************************************** 310this function just checks that we don't get ENOSYS back 311****************************************************************************/ 312static int have_syscall(void) 313{ 314 errno = 0; 315 316#if USE_SETRESUID 317 setresuid(-1,-1,-1); 318#endif 319 320#if USE_SETREUID 321 setreuid(-1,-1); 322#endif 323 324#if USE_SETEUID 325 seteuid(-1); 326#endif 327 328#if USE_SETUIDX 329 setuidx(ID_EFFECTIVE, -1); 330#endif 331 332 if (errno == ENOSYS) return -1; 333 334 return 0; 335} 336 337#ifdef AUTOCONF_TEST 338main() 339{ 340 if (getuid() != 0) { 341#if (defined(AIX) && defined(USE_SETREUID)) 342 /* setreuid is badly broken on AIX 4.1, we avoid it completely */ 343 fprintf(stderr,"avoiding possibly broken setreuid\n"); 344 exit(1); 345#endif 346 347 /* if not running as root then at least check to see if we get ENOSYS - this 348 handles Linux 2.0.x with glibc 2.1 */ 349 fprintf(stderr,"not running as root: checking for ENOSYS\n"); 350 exit(have_syscall()); 351 } 352 353 gain_root_privilege(); 354 gain_root_group_privilege(); 355 set_effective_gid(1); 356 set_effective_uid(1); 357 save_re_uid(); 358 restore_re_uid(); 359 gain_root_privilege(); 360 gain_root_group_privilege(); 361 become_user_permanently(1, 1); 362 setuid(0); 363 if (getuid() == 0) { 364 fprintf(stderr,"uid not set permanently\n"); 365 exit(1); 366 } 367 368 printf("OK\n"); 369 370 exit(0); 371} 372#endif 373