source: vendor/current/source3/lib/util_sec.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 13.6 KB
Line 
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 <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#define bool int
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 */
50static uid_t initial_uid;
51static gid_t initial_gid;
52
53/****************************************************************************
54remember what uid we got started as - this allows us to run correctly
55as non-root while catching trapdoor systems
56****************************************************************************/
57
58void sec_init(void)
59{
60 static int initialized;
61
62 if (!initialized) {
63
64#ifndef AUTOCONF_TEST
65 if (uid_wrapper_enabled()) {
66 setenv("UID_WRAPPER_MYUID", "1", 1);
67 }
68#endif
69
70 initial_uid = geteuid();
71 initial_gid = getegid();
72
73#ifndef AUTOCONF_TEST
74 if (uid_wrapper_enabled()) {
75 unsetenv("UID_WRAPPER_MYUID");
76 }
77#endif
78
79 initialized = 1;
80 }
81}
82
83/****************************************************************************
84some code (eg. winbindd) needs to know what uid we started as
85****************************************************************************/
86uid_t sec_initial_uid(void)
87{
88 return initial_uid;
89}
90
91/****************************************************************************
92some code (eg. winbindd, profiling shm) needs to know what gid we started as
93****************************************************************************/
94gid_t sec_initial_gid(void)
95{
96 return initial_gid;
97}
98
99/**
100 * @brief Check if we are running in root mode.
101 *
102 * @return If we samba root privileges it returns true, false otehrwise.
103 */
104bool root_mode(void)
105{
106 uid_t euid;
107
108 euid = geteuid();
109
110#ifndef AUTOCONF_TEST
111 if (uid_wrapper_enabled()) {
112 return (euid == initial_uid || euid == (uid_t)0);
113 }
114#endif
115
116 return (initial_uid == euid);
117}
118
119/****************************************************************************
120are we running in non-root mode?
121****************************************************************************/
122bool non_root_mode(void)
123{
124 return (initial_uid != (uid_t)0);
125}
126
127/****************************************************************************
128abort if we haven't set the uid correctly
129****************************************************************************/
130static void assert_uid(uid_t ruid, uid_t euid)
131{
132 if ((euid != (uid_t)-1 && geteuid() != euid) ||
133 (ruid != (uid_t)-1 && getuid() != ruid)) {
134 if (!non_root_mode()) {
135 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 smb_panic("failed to set uid\n");
139 exit(1);
140 }
141 }
142}
143
144/****************************************************************************
145abort if we haven't set the gid correctly
146****************************************************************************/
147static void assert_gid(gid_t rgid, gid_t egid)
148{
149 if ((egid != (gid_t)-1 && getegid() != egid) ||
150 (rgid != (gid_t)-1 && getgid() != rgid)) {
151 if (!non_root_mode()) {
152 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 smb_panic("failed to set gid\n");
157 exit(1);
158 }
159 }
160}
161
162/****************************************************************************
163 Gain root privilege before doing something.
164 We want to end up with ruid==euid==0
165****************************************************************************/
166void gain_root_privilege(void)
167{
168#if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
169 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 samba_setuid(0);
187
188 assert_uid(0, 0);
189}
190
191
192/****************************************************************************
193 Ensure our real and effective groups are zero.
194 we want to end up with rgid==egid==0
195****************************************************************************/
196void gain_root_group_privilege(void)
197{
198#if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
199 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 samba_setgid(0);
216
217 assert_gid(0, 0);
218}
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****************************************************************************/
233void set_effective_uid(uid_t uid)
234{
235#if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
236 /* Set the effective as well as the real uid. */
237 if (samba_setresuid(uid,uid,-1) == -1) {
238 if (errno == EAGAIN) {
239 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 assert_uid(-1, uid);
259}
260
261/****************************************************************************
262 Set *only* the effective gid.
263 we want to end up with rgid==0 and egid==gid
264****************************************************************************/
265void set_effective_gid(gid_t gid)
266{
267#if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
268 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 assert_gid(-1, gid);
284}
285
286static uid_t saved_euid, saved_ruid;
287static 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****************************************************************************/
293void save_re_uid(void)
294{
295 saved_ruid = getuid();
296 saved_euid = geteuid();
297}
298
299
300/****************************************************************************
301 and restore them!
302****************************************************************************/
303
304void restore_re_uid_fromroot(void)
305{
306#if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
307 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 assert_uid(saved_ruid, saved_euid);
322}
323
324void restore_re_uid(void)
325{
326 set_effective_uid(0);
327 restore_re_uid_fromroot();
328}
329
330/****************************************************************************
331 save the real and effective gid for later restoration. Used by the
332 getgroups code
333****************************************************************************/
334void save_re_gid(void)
335{
336 saved_rgid = getgid();
337 saved_egid = getegid();
338}
339
340/****************************************************************************
341 and restore them!
342****************************************************************************/
343void restore_re_gid(void)
344{
345#if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
346 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 assert_gid(saved_rgid, saved_egid);
361}
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****************************************************************************/
369int set_re_uid(void)
370{
371 uid_t uid = geteuid();
372
373#if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
374 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 assert_uid(uid, uid);
394 return 0;
395}
396
397
398/****************************************************************************
399 Become the specified uid and gid - permanently !
400 there should be no way back if possible
401****************************************************************************/
402void 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 gain_root_privilege();
410 gain_root_group_privilege();
411
412#if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
413 samba_setresgid(gid,gid,gid);
414 samba_setgid(gid);
415 samba_setresuid(uid,uid,uid);
416 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 assert_uid(uid, uid);
444 assert_gid(gid, gid);
445}
446
447/**********************************************************
448 Function to set thread specific credentials. Leave
449 saved-set uid/gid alone.Must be thread-safe code.
450**********************************************************/
451
452int set_thread_credentials(uid_t uid,
453 gid_t gid,
454 size_t setlen,
455 const gid_t *gidset)
456{
457#if defined(USE_LINUX_THREAD_CREDENTIALS)
458 /*
459 * With Linux thread-specific credentials
460 * we know we have setresuid/setresgid
461 * available.
462 */
463
464 /* Become root. */
465 /* Set ru=0, eu=0 */
466 if (samba_setresuid(0, 0, -1) != 0) {
467 return -1;
468 }
469 /* Set our primary gid. */
470 /* Set rg=gid, eg=gid */
471 if (samba_setresgid(gid, gid, -1) != 0) {
472 return -1;
473 }
474 /* Set extra groups list. */
475 if (samba_setgroups(setlen, gidset) != 0) {
476 return -1;
477 }
478 /* Become the requested user. */
479 /* Set ru=uid, eu=uid */
480 if (samba_setresuid(uid, uid, -1) != 0) {
481 return -1;
482 }
483 if (geteuid() != uid || getuid() != uid ||
484 getegid() != gid || getgid() != gid) {
485 smb_panic("set_thread_credentials failed\n");
486 return -1;
487 }
488 return 0;
489#else
490 errno = ENOSYS;
491 return -1;
492#endif
493}
494
495#ifdef AUTOCONF_TEST
496
497/****************************************************************************
498this function just checks that we don't get ENOSYS back
499****************************************************************************/
500static int have_syscall(void)
501{
502 errno = 0;
503
504#if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
505 samba_setresuid(-1,-1,-1);
506#endif
507
508#if USE_SETREUID
509 samba_setreuid(-1,-1);
510#endif
511
512#if USE_SETEUID
513 samba_seteuid(-1);
514#endif
515
516#if USE_SETUIDX
517 samba_setuidx(ID_EFFECTIVE, -1);
518#endif
519
520 if (errno == ENOSYS) return -1;
521
522 return 0;
523}
524
525main()
526{
527 if (getuid() != 0) {
528#if (defined(AIX) && defined(USE_SETREUID))
529 /* setreuid is badly broken on AIX 4.1, we avoid it completely */
530 fprintf(stderr,"avoiding possibly broken setreuid\n");
531 exit(1);
532#endif
533
534 /* if not running as root then at least check to see if we get ENOSYS - this
535 handles Linux 2.0.x with glibc 2.1 */
536 fprintf(stderr,"not running as root: checking for ENOSYS\n");
537 exit(have_syscall());
538 }
539
540 gain_root_privilege();
541 gain_root_group_privilege();
542 set_effective_gid(1);
543 set_effective_uid(1);
544 save_re_uid();
545 restore_re_uid();
546 gain_root_privilege();
547 gain_root_group_privilege();
548 become_user_permanently(1, 1);
549 samba_setuid(0);
550 if (getuid() == 0) {
551 fprintf(stderr,"uid not set permanently\n");
552 exit(1);
553 }
554
555 printf("OK\n");
556
557 exit(0);
558}
559#endif
560
561/****************************************************************************
562Check if we are setuid root. Used in libsmb and smbpasswd paranoia checks.
563****************************************************************************/
564bool is_setuid_root(void)
565{
566 return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
567}
Note: See TracBrowser for help on using the repository browser.