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 regression 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 8718 : void sec_init(void)
59 : {
60 142 : static int initialized;
61 :
62 8718 : if (!initialized) {
63 :
64 : #ifndef AUTOCONF_TEST
65 5105 : if (uid_wrapper_enabled()) {
66 5105 : setenv("UID_WRAPPER_MYUID", "1", 1);
67 : }
68 : #endif
69 :
70 5105 : initial_uid = geteuid();
71 5105 : initial_gid = getegid();
72 :
73 : #ifndef AUTOCONF_TEST
74 5105 : if (uid_wrapper_enabled()) {
75 5105 : unsetenv("UID_WRAPPER_MYUID");
76 : }
77 : #endif
78 :
79 5105 : initialized = 1;
80 : }
81 8718 : }
82 :
83 : /****************************************************************************
84 : some code (eg. winbindd) needs to know what uid we started as
85 : ****************************************************************************/
86 31164 : uid_t sec_initial_uid(void)
87 : {
88 31164 : return initial_uid;
89 : }
90 :
91 : /****************************************************************************
92 : some code (eg. winbindd, profiling shm) needs to know what gid we started as
93 : ****************************************************************************/
94 598 : gid_t sec_initial_gid(void)
95 : {
96 598 : 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 405340 : bool root_mode(void)
105 : {
106 193 : uid_t euid;
107 :
108 405340 : euid = geteuid();
109 :
110 : #ifndef AUTOCONF_TEST
111 405340 : if (uid_wrapper_enabled()) {
112 405533 : 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 9925276 : bool non_root_mode(void)
123 : {
124 9925276 : return (initial_uid != (uid_t)0);
125 : }
126 :
127 : /****************************************************************************
128 : abort if we haven't set the uid correctly
129 : ****************************************************************************/
130 9920070 : static void assert_uid(uid_t ruid, uid_t euid)
131 : {
132 9920070 : if ((euid != (uid_t)-1 && geteuid() != euid) ||
133 8302 : (ruid != (uid_t)-1 && getuid() != ruid)) {
134 23 : 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 9920070 : }
143 :
144 : /****************************************************************************
145 : abort if we haven't set the gid correctly
146 : ****************************************************************************/
147 9920070 : static void assert_gid(gid_t rgid, gid_t egid)
148 : {
149 9920070 : if ((egid != (gid_t)-1 && getegid() != egid) ||
150 8302 : (rgid != (gid_t)-1 && getgid() != rgid)) {
151 23 : 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 9920070 : }
161 :
162 : /****************************************************************************
163 : Gain root privilege before doing something.
164 : We want to end up with ruid==euid==0
165 : ****************************************************************************/
166 4159 : void gain_root_privilege(void)
167 : {
168 : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
169 4159 : 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 4159 : samba_setuid(0);
187 :
188 4159 : assert_uid(0, 0);
189 4159 : }
190 :
191 :
192 : /****************************************************************************
193 : Ensure our real and effective groups are zero.
194 : we want to end up with rgid==egid==0
195 : ****************************************************************************/
196 4159 : void gain_root_group_privilege(void)
197 : {
198 : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
199 4159 : 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 4159 : samba_setgid(0);
216 :
217 4159 : assert_gid(0, 0);
218 4159 : }
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 9911752 : 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 9911752 : 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 9911752 : assert_uid(-1, uid);
259 9911752 : }
260 :
261 : /****************************************************************************
262 : Set *only* the effective gid.
263 : we want to end up with rgid==0 and egid==gid
264 : ****************************************************************************/
265 9911752 : void set_effective_gid(gid_t gid)
266 : {
267 : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
268 9911752 : 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 9911752 : assert_gid(-1, gid);
284 9911752 : }
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 0 : void save_re_gid(void)
335 : {
336 0 : saved_rgid = getgid();
337 0 : saved_egid = getegid();
338 0 : }
339 :
340 : /****************************************************************************
341 : and restore them!
342 : ****************************************************************************/
343 0 : void restore_re_gid(void)
344 : {
345 : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
346 0 : 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 0 : assert_gid(saved_rgid, saved_egid);
361 0 : }
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 4159 : 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 4159 : gain_root_privilege();
410 4159 : gain_root_group_privilege();
411 :
412 : #if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
413 4159 : samba_setresgid(gid,gid,gid);
414 4159 : samba_setgid(gid);
415 4159 : samba_setresuid(uid,uid,uid);
416 4159 : 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 4159 : assert_uid(uid, uid);
444 4159 : assert_gid(gid, gid);
445 4159 : }
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 10077 : 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 10077 : if (cache.active &&
476 10058 : cache.uid == uid &&
477 10056 : cache.gid == gid &&
478 10056 : cache.setlen == setlen &&
479 10056 : (const gid_t *)cache.gidset == gidset)
480 : {
481 10056 : return 0;
482 : }
483 : #endif /* HAVE___THREAD */
484 :
485 : /* Become root. */
486 : /* Set ru=0, eu=0 */
487 21 : if (samba_setresuid(0, 0, -1) != 0) {
488 0 : return -1;
489 : }
490 : /* Set our primary gid. */
491 : /* Set rg=gid, eg=gid */
492 21 : if (samba_setresgid(gid, gid, -1) != 0) {
493 0 : return -1;
494 : }
495 : /* Set extra groups list. */
496 21 : if (samba_setgroups(setlen, gidset) != 0) {
497 0 : return -1;
498 : }
499 : /* Become the requested user. */
500 : /* Set ru=uid, eu=uid */
501 21 : if (samba_setresuid(uid, uid, -1) != 0) {
502 0 : return -1;
503 : }
504 42 : if (geteuid() != uid || getuid() != uid ||
505 42 : getegid() != gid || getgid() != gid) {
506 0 : smb_panic("set_thread_credentials failed\n");
507 : return -1;
508 : }
509 :
510 : #ifdef HAVE___THREAD
511 21 : cache.active = true;
512 21 : cache.uid = uid;
513 21 : cache.gid = gid;
514 21 : cache.setlen = setlen;
515 21 : cache.gidset = (uintptr_t)gidset;
516 : #endif /* HAVE___THREAD */
517 :
518 21 : 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 18545 : bool is_setuid_root(void)
596 : {
597 18545 : return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
598 : }
|