pyldb: avoid segfault when adding an element with no name
[kamenim/samba-autobuild/.git] / source3 / lib / util_sec.c
index d59b1b0471664a7b9a0f67cd4337a1418b67f89f..974e458b06ed5d705bff6d7bc91bba0d7f08cfd8 100644 (file)
@@ -5,7 +5,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #ifndef AUTOCONF_TEST
 #include "includes.h"
+#include "system/passwd.h" /* uid_wrapper */
+#include "../lib/util/setid.h"
+
 #else
 /* we are running this code in autoconf test mode to see which type of setuid
    function works */
 #if defined(HAVE_UNISTD_H)
 #include <unistd.h>
 #endif
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/types.h>
@@ -40,7 +43,6 @@
 
 #define DEBUG(x, y) printf y
 #define smb_panic(x) exit(1)
-#define BOOL int
 #endif
 
 /* are we running as non-root? This is used by the regresison test code,
@@ -52,10 +54,30 @@ static gid_t initial_gid;
 remember what uid we got started as - this allows us to run correctly
 as non-root while catching trapdoor systems
 ****************************************************************************/
+
 void sec_init(void)
 {
-       initial_uid = geteuid();
-       initial_gid = getegid();
+       static int initialized;
+
+       if (!initialized) {
+
+#ifndef AUTOCONF_TEST
+               if (uid_wrapper_enabled()) {
+                       setenv("UID_WRAPPER_MYUID", "1", 1);
+               }
+#endif
+
+               initial_uid = geteuid();
+               initial_gid = getegid();
+
+#ifndef AUTOCONF_TEST
+               if (uid_wrapper_enabled()) {
+                       unsetenv("UID_WRAPPER_MYUID");
+               }
+#endif
+
+               initialized = 1;
+       }
 }
 
 /****************************************************************************
@@ -74,10 +96,30 @@ gid_t sec_initial_gid(void)
        return initial_gid;
 }
 
+/**
+ * @brief Check if we are running in root mode.
+ *
+ * @return If we samba root privileges it returns true, false otehrwise.
+ */
+bool root_mode(void)
+{
+       uid_t euid;
+
+       euid = geteuid();
+
+#ifndef AUTOCONF_TEST
+       if (uid_wrapper_enabled()) {
+               return (euid == initial_uid || euid == (uid_t)0);
+       }
+#endif
+
+       return (initial_uid == euid);
+}
+
 /****************************************************************************
 are we running in non-root mode?
 ****************************************************************************/
-BOOL non_root_mode(void)
+bool non_root_mode(void)
 {
        return (initial_uid != (uid_t)0);
 }
@@ -123,25 +165,25 @@ static void assert_gid(gid_t rgid, gid_t egid)
 ****************************************************************************/
 void gain_root_privilege(void)
 {      
-#if USE_SETRESUID
-       setresuid(0,0,0);
+#if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
+       samba_setresuid(0,0,0);
 #endif
     
 #if USE_SETEUID
-       seteuid(0);
+       samba_seteuid(0);
 #endif
 
 #if USE_SETREUID
-       setreuid(0, 0);
+       samba_setreuid(0, 0);
 #endif
 
 #if USE_SETUIDX
-       setuidx(ID_EFFECTIVE, 0);
-       setuidx(ID_REAL, 0);
+       samba_setuidx(ID_EFFECTIVE, 0);
+       samba_setuidx(ID_REAL, 0);
 #endif
 
        /* this is needed on some systems */
-       setuid(0);
+       samba_setuid(0);
 
        assert_uid(0, 0);
 }
@@ -153,49 +195,64 @@ void gain_root_privilege(void)
 ****************************************************************************/
 void gain_root_group_privilege(void)
 {
-#if USE_SETRESUID
-       setresgid(0,0,0);
+#if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
+       samba_setresgid(0,0,0);
 #endif
 
 #if USE_SETREUID
-       setregid(0,0);
+       samba_setregid(0,0);
 #endif
 
 #if USE_SETEUID
-       setegid(0);
+       samba_setegid(0);
 #endif
 
 #if USE_SETUIDX
-       setgidx(ID_EFFECTIVE, 0);
-       setgidx(ID_REAL, 0);
+       samba_setgidx(ID_EFFECTIVE, 0);
+       samba_setgidx(ID_REAL, 0);
 #endif
 
-       setgid(0);
+       samba_setgid(0);
 
        assert_gid(0, 0);
 }
 
 
 /****************************************************************************
- Set *only* the effective uid.
- we want to end up with ruid==0 and euid==uid
+ Set effective uid, and possibly the real uid too.
+ We want to end up with either:
+  
+   ruid==uid and euid==uid
+
+ or
+
+   ruid==0 and euid==uid
+
+ depending on what the local OS will allow us to regain root from.
 ****************************************************************************/
 void set_effective_uid(uid_t uid)
 {
-#if USE_SETRESUID
-       setresuid(-1,uid,-1);
+#if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
+        /* Set the effective as well as the real uid. */
+       if (samba_setresuid(uid,uid,-1) == -1) {
+               if (errno == EAGAIN) {
+                       DEBUG(0, ("samba_setresuid failed with EAGAIN. uid(%d) "
+                                 "might be over its NPROC limit\n",
+                                 (int)uid));
+               }
+       }
 #endif
 
 #if USE_SETREUID
-       setreuid(-1,uid);
+       samba_setreuid(-1,uid);
 #endif
 
 #if USE_SETEUID
-       seteuid(uid);
+       samba_seteuid(uid);
 #endif
 
 #if USE_SETUIDX
-       setuidx(ID_EFFECTIVE, uid);
+       samba_setuidx(ID_EFFECTIVE, uid);
 #endif
 
        assert_uid(-1, uid);
@@ -207,26 +264,27 @@ void set_effective_uid(uid_t uid)
 ****************************************************************************/
 void set_effective_gid(gid_t gid)
 {
-#if USE_SETRESUID
-       setresgid(-1,gid,-1);
+#if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
+       samba_setresgid(-1,gid,-1);
 #endif
 
 #if USE_SETREUID
-       setregid(-1,gid);
+       samba_setregid(-1,gid);
 #endif
 
 #if USE_SETEUID
-       setegid(gid);
+       samba_setegid(gid);
 #endif
 
 #if USE_SETUIDX
-       setgidx(ID_EFFECTIVE, gid);
+       samba_setgidx(ID_EFFECTIVE, gid);
 #endif
 
        assert_gid(-1, gid);
 }
 
 static uid_t saved_euid, saved_ruid;
+static gid_t saved_egid, saved_rgid;
 
 /****************************************************************************
  save the real and effective uid for later restoration. Used by the quotas
@@ -242,28 +300,67 @@ void save_re_uid(void)
 /****************************************************************************
  and restore them!
 ****************************************************************************/
-void restore_re_uid(void)
-{
-       set_effective_uid(0);
 
-#if USE_SETRESUID
-       setresuid(saved_ruid, saved_euid, -1);
+void restore_re_uid_fromroot(void)
+{
+#if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
+       samba_setresuid(saved_ruid, saved_euid, -1);
 #elif USE_SETREUID
-       setreuid(saved_ruid, -1);
-       setreuid(-1,saved_euid);
+       samba_setreuid(saved_ruid, -1);
+       samba_setreuid(-1,saved_euid);
 #elif USE_SETUIDX
-       setuidx(ID_REAL, saved_ruid);
-       setuidx(ID_EFFECTIVE, saved_euid);
+       samba_setuidx(ID_REAL, saved_ruid);
+       samba_setuidx(ID_EFFECTIVE, saved_euid);
 #else
        set_effective_uid(saved_euid);
        if (getuid() != saved_ruid)
-               setuid(saved_ruid);
+               samba_setuid(saved_ruid);
        set_effective_uid(saved_euid);
 #endif
 
        assert_uid(saved_ruid, saved_euid);
 }
 
+void restore_re_uid(void)
+{
+       set_effective_uid(0);
+       restore_re_uid_fromroot();
+}
+
+/****************************************************************************
+ save the real and effective gid for later restoration. Used by the 
+ getgroups code
+****************************************************************************/
+void save_re_gid(void)
+{
+       saved_rgid = getgid();
+       saved_egid = getegid();
+}
+
+/****************************************************************************
+ and restore them!
+****************************************************************************/
+void restore_re_gid(void)
+{
+#if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
+       samba_setresgid(saved_rgid, saved_egid, -1);
+#elif USE_SETREUID
+       samba_setregid(saved_rgid, -1);
+       samba_setregid(-1,saved_egid);
+#elif USE_SETUIDX
+       samba_setgidx(ID_REAL, saved_rgid);
+       samba_setgidx(ID_EFFECTIVE, saved_egid);
+#else
+       set_effective_gid(saved_egid);
+       if (getgid() != saved_rgid)
+               samba_setgid(saved_rgid);
+       set_effective_gid(saved_egid);
+#endif
+
+       assert_gid(saved_rgid, saved_egid);
+}
+
+
 /****************************************************************************
  set the real AND effective uid to the current effective uid in a way that
  allows root to be regained.
@@ -273,14 +370,14 @@ int set_re_uid(void)
 {
        uid_t uid = geteuid();
 
-#if USE_SETRESUID
-       setresuid(geteuid(), -1, -1);
+#if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
+       samba_setresuid(uid, uid, -1);
 #endif
 
 #if USE_SETREUID
-       setreuid(0, 0);
-       setreuid(uid, -1);
-       setreuid(-1, uid);
+       samba_setreuid(0, 0);
+       samba_setreuid(uid, -1);
+       samba_setreuid(-1, uid);
 #endif
 
 #if USE_SETEUID
@@ -312,41 +409,116 @@ void become_user_permanently(uid_t uid, gid_t gid)
        gain_root_privilege();
        gain_root_group_privilege();
 
-#if USE_SETRESUID
-       setresgid(gid,gid,gid);
-       setgid(gid);
-       setresuid(uid,uid,uid);
-       setuid(uid);
+#if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
+       samba_setresgid(gid,gid,gid);
+       samba_setgid(gid);
+       samba_setresuid(uid,uid,uid);
+       samba_setuid(uid);
 #endif
 
 #if USE_SETREUID
-       setregid(gid,gid);
-       setgid(gid);
-       setreuid(uid,uid);
-       setuid(uid);
+       samba_setregid(gid,gid);
+       samba_setgid(gid);
+       samba_setreuid(uid,uid);
+       samba_setuid(uid);
 #endif
 
 #if USE_SETEUID
-       setegid(gid);
-       setgid(gid);
-       setuid(uid);
-       seteuid(uid);
-       setuid(uid);
+       samba_setegid(gid);
+       samba_setgid(gid);
+       samba_setuid(uid);
+       samba_seteuid(uid);
+       samba_setuid(uid);
 #endif
 
 #if USE_SETUIDX
-       setgidx(ID_REAL, gid);
-       setgidx(ID_EFFECTIVE, gid);
-       setgid(gid);
-       setuidx(ID_REAL, uid);
-       setuidx(ID_EFFECTIVE, uid);
-       setuid(uid);
+       samba_setgidx(ID_REAL, gid);
+       samba_setgidx(ID_EFFECTIVE, gid);
+       samba_setgid(gid);
+       samba_setuidx(ID_REAL, uid);
+       samba_setuidx(ID_EFFECTIVE, uid);
+       samba_setuid(uid);
 #endif
        
        assert_uid(uid, uid);
        assert_gid(gid, gid);
 }
 
+/**********************************************************
+ Function to set thread specific credentials. Leave
+ saved-set uid/gid alone.Must be thread-safe code.
+**********************************************************/
+
+int set_thread_credentials(uid_t uid,
+                       gid_t gid,
+                       size_t setlen,
+                       const gid_t *gidset)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+       /*
+        * With Linux thread-specific credentials
+        * we know we have setresuid/setresgid
+        * available.
+        */
+#ifdef HAVE___THREAD
+       static struct {
+               bool active;
+               uid_t uid;
+               gid_t gid;
+               size_t setlen;
+               uintptr_t gidset;
+       } __thread cache;
+
+       if (cache.active &&
+           cache.uid == uid &&
+           cache.gid == gid &&
+           cache.setlen == setlen &&
+           (const gid_t *)cache.gidset == gidset)
+       {
+               return 0;
+       }
+#endif /* HAVE___THREAD */
+
+       /* Become root. */
+       /* Set ru=0, eu=0 */
+       if (samba_setresuid(0, 0, -1) != 0) {
+               return -1;
+       }
+       /* Set our primary gid. */
+       /* Set rg=gid, eg=gid */
+       if (samba_setresgid(gid, gid, -1) != 0) {
+               return -1;
+       }
+       /* Set extra groups list. */
+       if (samba_setgroups(setlen, gidset) != 0) {
+               return -1;
+       }
+       /* Become the requested user. */
+       /* Set ru=uid, eu=uid */
+       if (samba_setresuid(uid, uid, -1) != 0) {
+               return -1;
+       }
+       if (geteuid() != uid || getuid() != uid ||
+                       getegid() != gid || getgid() != gid) {
+               smb_panic("set_thread_credentials failed\n");
+               return -1;
+       }
+
+#ifdef HAVE___THREAD
+       cache.active = true;
+       cache.uid = uid;
+       cache.gid = gid;
+       cache.setlen = setlen;
+       cache.gidset = (uintptr_t)gidset;
+#endif /* HAVE___THREAD */
+
+       return 0;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
 #ifdef AUTOCONF_TEST
 
 /****************************************************************************
@@ -356,28 +528,29 @@ static int have_syscall(void)
 {
        errno = 0;
 
-#if USE_SETRESUID
-       setresuid(-1,-1,-1);
+#if defined(USE_SETRESUID) || defined(HAVE_LINUX_THREAD_CREDENTIALS)
+       samba_setresuid(-1,-1,-1);
 #endif
 
 #if USE_SETREUID
-       setreuid(-1,-1);
+       samba_setreuid(-1,-1);
 #endif
 
 #if USE_SETEUID
-       seteuid(-1);
+       samba_seteuid(-1);
 #endif
 
 #if USE_SETUIDX
-       setuidx(ID_EFFECTIVE, -1);
+       samba_setuidx(ID_EFFECTIVE, -1);
 #endif
 
-       if (errno == ENOSYS) return -1;
-       
+       if (errno == ENOSYS) {
+               return -1;
+       }
        return 0;
 }
 
-main()
+int main(void)
 {
         if (getuid() != 0) {
 #if (defined(AIX) && defined(USE_SETREUID))
@@ -401,7 +574,7 @@ main()
        gain_root_privilege();
        gain_root_group_privilege();
        become_user_permanently(1, 1);
-       setuid(0);
+       samba_setuid(0);
        if (getuid() == 0) {
                fprintf(stderr,"uid not set permanently\n");
                exit(1);
@@ -416,7 +589,7 @@ main()
 /****************************************************************************
 Check if we are setuid root.  Used in libsmb and smbpasswd paranoia checks.
 ****************************************************************************/
-BOOL is_setuid_root(void) 
+bool is_setuid_root(void) 
 {
        return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
 }