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