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