lib: Remove unused client_addr()
[samba.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 <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 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
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 /****************************************************************************
84 some code (eg. winbindd) needs to know what uid we started as
85 ****************************************************************************/
86 uid_t sec_initial_uid(void)
87 {
88         return initial_uid;
89 }
90
91 /****************************************************************************
92 some code (eg. winbindd, profiling shm) needs to know what gid we started as
93 ****************************************************************************/
94 gid_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  */
104 bool 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 /****************************************************************************
120 are we running in non-root mode?
121 ****************************************************************************/
122 bool non_root_mode(void)
123 {
124         return (initial_uid != (uid_t)0);
125 }
126
127 /****************************************************************************
128 abort if we haven't set the uid correctly
129 ****************************************************************************/
130 static 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 /****************************************************************************
145 abort if we haven't set the gid correctly
146 ****************************************************************************/
147 static 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 ****************************************************************************/
166 void gain_root_privilege(void)
167 {       
168 #if defined(USE_SETRESUID) || defined(HAVE_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 ****************************************************************************/
196 void gain_root_group_privilege(void)
197 {
198 #if defined(USE_SETRESUID) || defined(HAVE_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 ****************************************************************************/
233 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         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 ****************************************************************************/
265 void set_effective_gid(gid_t gid)
266 {
267 #if defined(USE_SETRESUID) || defined(HAVE_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
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 void save_re_uid(void)
294 {
295         saved_ruid = getuid();
296         saved_euid = geteuid();
297 }
298
299
300 /****************************************************************************
301  and restore them!
302 ****************************************************************************/
303
304 void restore_re_uid_fromroot(void)
305 {
306 #if defined(USE_SETRESUID) || defined(HAVE_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
324 void 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 ****************************************************************************/
334 void save_re_gid(void)
335 {
336         saved_rgid = getgid();
337         saved_egid = getegid();
338 }
339
340 /****************************************************************************
341  and restore them!
342 ****************************************************************************/
343 void restore_re_gid(void)
344 {
345 #if defined(USE_SETRESUID) || defined(HAVE_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 ****************************************************************************/
369 int set_re_uid(void)
370 {
371         uid_t uid = geteuid();
372
373 #if defined(USE_SETRESUID) || defined(HAVE_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 ****************************************************************************/
402 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         gain_root_privilege();
410         gain_root_group_privilege();
411
412 #if defined(USE_SETRESUID) || defined(HAVE_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 #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 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         if (cache.active &&
476             cache.uid == uid &&
477             cache.gid == gid &&
478             cache.setlen == setlen &&
479             (const gid_t *)cache.gidset == gidset)
480         {
481                 return 0;
482         }
483 #endif /* HAVE___THREAD */
484
485         /* Become root. */
486         /* Set ru=0, eu=0 */
487         if (samba_setresuid(0, 0, -1) != 0) {
488                 return -1;
489         }
490         /* Set our primary gid. */
491         /* Set rg=gid, eg=gid */
492         if (samba_setresgid(gid, gid, -1) != 0) {
493                 return -1;
494         }
495         /* Set extra groups list. */
496         if (samba_setgroups(setlen, gidset) != 0) {
497                 return -1;
498         }
499         /* Become the requested user. */
500         /* Set ru=uid, eu=uid */
501         if (samba_setresuid(uid, uid, -1) != 0) {
502                 return -1;
503         }
504         if (geteuid() != uid || getuid() != uid ||
505                         getegid() != gid || getgid() != gid) {
506                 smb_panic("set_thread_credentials failed\n");
507                 return -1;
508         }
509
510 #ifdef HAVE___THREAD
511         cache.active = true;
512         cache.uid = uid;
513         cache.gid = gid;
514         cache.setlen = setlen;
515         cache.gidset = (uintptr_t)gidset;
516 #endif /* HAVE___THREAD */
517
518         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 bool is_setuid_root(void) 
596 {
597         return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
598 }