~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/lib/util_sec.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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)
 
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)
 
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)
 
78
{
 
79
        return initial_gid;
 
80
}
 
81
 
 
82
/****************************************************************************
 
83
are we running in non-root mode?
 
84
****************************************************************************/
 
85
bool non_root_mode(void)
 
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)
 
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)
 
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)
 
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)
 
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)
 
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)
 
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)
 
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)
 
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)
 
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)
 
298
{
 
299
        saved_rgid = getgid();
 
300
        saved_egid = getegid();
 
301
}
 
302
 
 
303
/****************************************************************************
 
304
 and restore them!
 
305
****************************************************************************/
 
306
void restore_re_gid(void)
 
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)
 
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)
 
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)
 
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()
 
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) 
 
480
{
 
481
        return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
 
482
}