Provide a libsmbclient interface for programs requiring threads
[ira/wip.git] / source3 / lib / util_sec.c
index 068be684f36a4c00b6409479273a2aa825d56eac..d7984ac99965fe0cb25f8879044998b2fc069c87 100644 (file)
@@ -1,12 +1,11 @@
 /*
-   Unix SMB/Netbios implementation.
-   Version 2.0
+   Unix SMB/CIFS implementation.
    Copyright (C) Jeremy Allison 1998.
    rewritten for version 2.0.6 by Tridge
 
    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"
-extern int DEBUGLEVEL;
 #else
 /* we are running this code in autoconf test mode to see which type of setuid
    function works */
@@ -42,8 +39,54 @@ extern int DEBUGLEVEL;
 
 #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,
+   and potentially also for sites that want non-root smbd */
+static uid_t initial_uid;
+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)
+{
+       static int initialized;
+
+       if (!initialized) {
+               initial_uid = geteuid();
+               initial_gid = getegid();
+               initialized = 1;
+       }
+}
+
+/****************************************************************************
+some code (eg. winbindd) needs to know what uid we started as
+****************************************************************************/
+uid_t sec_initial_uid(void)
+{
+       return initial_uid;
+}
+
+/****************************************************************************
+some code (eg. winbindd, profiling shm) needs to know what gid we started as
+****************************************************************************/
+gid_t sec_initial_gid(void)
+{
+       return initial_gid;
+}
+
+/****************************************************************************
+are we running in non-root mode?
+****************************************************************************/
+bool non_root_mode(void)
+{
+       return (initial_uid != (uid_t)0);
+}
+
 /****************************************************************************
 abort if we haven't set the uid correctly
 ****************************************************************************/
@@ -51,11 +94,13 @@ static void assert_uid(uid_t ruid, uid_t euid)
 {
        if ((euid != (uid_t)-1 && geteuid() != euid) ||
            (ruid != (uid_t)-1 && getuid() != ruid)) {
-               DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
-                        (int)ruid, (int)euid,
-                        (int)getuid(), (int)geteuid()));
-               smb_panic("failed to set uid\n");
-               exit(1);
+               if (!non_root_mode()) {
+                       DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
+                                (int)ruid, (int)euid,
+                                (int)getuid(), (int)geteuid()));
+                       smb_panic("failed to set uid\n");
+                       exit(1);
+               }
        }
 }
 
@@ -66,12 +111,14 @@ static void assert_gid(gid_t rgid, gid_t egid)
 {
        if ((egid != (gid_t)-1 && getegid() != egid) ||
            (rgid != (gid_t)-1 && getgid() != rgid)) {
-               DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
-                        (int)rgid, (int)egid,
-                        (int)getgid(), (int)getegid(),
-                        (int)getuid(), (int)geteuid()));
-               smb_panic("failed to set gid\n");
-               exit(1);
+               if (!non_root_mode()) {
+                       DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
+                                (int)rgid, (int)egid,
+                                (int)getgid(), (int)getegid(),
+                                (int)getuid(), (int)geteuid()));
+                       smb_panic("failed to set gid\n");
+                       exit(1);
+               }
        }
 }
 
@@ -135,13 +182,28 @@ void gain_root_group_privilege(void)
 
 
 /****************************************************************************
- 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);
+        /* Set the effective as well as the real uid. */
+       if (setresuid(uid,uid,-1) == -1) {
+               if (errno == EAGAIN) {
+                       DEBUG(0, ("setresuid failed with EAGAIN. uid(%d) "
+                                 "might be over its NPROC limit\n",
+                                 (int)uid));
+               }
+       }
 #endif
 
 #if USE_SETREUID
@@ -185,6 +247,7 @@ void set_effective_gid(gid_t 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
@@ -200,10 +263,9 @@ void save_re_uid(void)
 /****************************************************************************
  and restore them!
 ****************************************************************************/
-void restore_re_uid(void)
-{
-       set_effective_uid(0);
 
+void restore_re_uid_fromroot(void)
+{
 #if USE_SETRESUID
        setresuid(saved_ruid, saved_euid, -1);
 #elif USE_SETREUID
@@ -222,6 +284,46 @@ void restore_re_uid(void)
        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 USE_SETRESUID
+       setresgid(saved_rgid, saved_egid, -1);
+#elif USE_SETREUID
+       setregid(saved_rgid, -1);
+       setregid(-1,saved_egid);
+#elif USE_SETUIDX
+       setgidx(ID_REAL, saved_rgid);
+       setgidx(ID_EFFECTIVE, saved_egid);
+#else
+       set_effective_gid(saved_egid);
+       if (getgid() != saved_rgid)
+               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.
@@ -370,3 +472,11 @@ main()
        exit(0);
 }
 #endif
+
+/****************************************************************************
+Check if we are setuid root.  Used in libsmb and smbpasswd paranoia checks.
+****************************************************************************/
+bool is_setuid_root(void) 
+{
+       return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
+}