]> WPIA git - gigi.git/commitdiff
add: support configuring SetUID behavior
authorLucas Werkmeister <mail@lucaswerkmeister.de>
Wed, 7 Sep 2016 13:03:47 +0000 (15:03 +0200)
committerLucas Werkmeister <mail@lucaswerkmeister.de>
Tue, 20 Sep 2016 16:00:33 +0000 (18:00 +0200)
- It is now possible to skip the setuid step altogether by setting both
  UID and GID to the special value -1.
- The Java code now verifies that the values are in range for an
  unsigned 16-bit ID.
- The C code now verifies that the cast from jint to uid_t/gid_t does
  not overflow.
- The C code now skips setuid() or setgid() if the real and effective ID
  are already the desired ID.

The 16-bit limit is somewhat arbitrary. Some old UNIX systems, such as
PWB/UNIX, supported only 8-bit IDs (see for example
/usr/man/man2/getuid.2 in Henry Spencer’s tarball); Wikipedia claims
that some other UNIX systems used 15-bit values, but does not specify
which systems; Linux originally supported 16-bit IDs but then added
support for 32-bit IDs with new syscalls in Linux 2.4. On Debian
systems, the nobody user (default setuid target) is 65534, so we need to
allow at least 16-bit IDs, otherwise the default value is invalid.

Change-Id: I66600572016b18d5ff550560048cdf691dec85e8

natives/org_cacert_gigi_natives_SetUID.c
src/org/cacert/gigi/Launcher.java

index 6c94d619a397dfdf891d25136753febe390be827..1b2350b4ab856102906013b6fcf80dfe8b0e6da5 100644 (file)
@@ -18,20 +18,45 @@ static jobject getStatus(JNIEnv *env, int successCode, const char * message) {
 }
 
 JNIEXPORT jobject JNICALL Java_org_cacert_gigi_natives_SetUID_setUid
-        (JNIEnv *env, jobject obj, jint uid, jint gid) {
+        (JNIEnv *env, jobject obj, jint uid_, jint gid_) {
 
     /* We don't need the reference for the object/class we are working on */
     (void)obj;
+    /* Fix uid and gid types */
+    uid_t uid = (uid_t)uid_;
+    if ((jint)uid != uid_) {
+      return getStatus(env, 0, "UID does not fit in uid_t type.");
+    }
+    gid_t gid = (gid_t)gid_;
+    if ((jint)gid != gid_) {
+      return getStatus(env, 0, "GID does not fit in gid_t type.");
+    }
 
-    if(setgid((int)gid)) {
-        return (jobject)getStatus(env, 0, "Error while setting GID.");
+    unsigned char work = 0;
+
+    if(getgid() != gid || getegid() != gid) {
+        if(setgid(gid)) {
+            return getStatus(env, 0, "Error while setting GID.");
+        }
+        work |= 1;
     }
 
-    if(setuid((int)uid)) {
-        return (jobject)getStatus(env, 0, "Error while setting UID.");
+    if(getuid() != uid || geteuid() != uid) {
+        if(setuid(uid)) {
+            return getStatus(env, 0, "Error while setting UID.");
+        }
+        work |= 2;
     }
 
-    return (jobject)getStatus(env, 1, "Successfully set uid/gid.");
+    char *status;
+    switch (work) {
+    case 0: status = "UID and GID already set."; break;
+    case 1: status = "Successfully set GID (UID already set)."; break;
+    case 2: status = "Successfully set UID (GID already set)."; break;
+    case 3: status = "Successfully set UID and GID."; break;
+    default: return getStatus(env, 0, "Unexpected internal state.");
+    }
+    return getStatus(env, 1, status);
 }
 
 #ifdef __cplusplus
index 5f767a63956a3da4ce8cb4be5256e8403b77da68..7c588d8e95a28b49183735478489b2f09e6309f0 100644 (file)
@@ -132,9 +132,23 @@ public class Launcher {
 
         s.start();
         if ((isSystemPort(ServerConstants.getSecurePort()) || isSystemPort(ServerConstants.getPort())) && !System.getProperty("os.name").toLowerCase().contains("win")) {
-            SetUID uid = new SetUID();
-            if ( !uid.setUid(65536 - 2, 65536 - 2).getSuccess()) {
-                Log.getLogger(Launcher.class).warn("Couldn't set uid!");
+            String uid_s = conf.getMainProps().getProperty("gigi.uid", Integer.toString(65536 - 2));
+            String gid_s = conf.getMainProps().getProperty("gigi.gid", Integer.toString(65536 - 2));
+            try {
+                int uid = Integer.parseInt(uid_s);
+                int gid = Integer.parseInt(gid_s);
+                if (uid == -1 && gid == -1) {
+                    // skip setuid step
+                } else if (uid > 0 && gid > 0 && uid < 65536 && gid < 65536) {
+                    SetUID.Status status = new SetUID().setUid(uid, gid);
+                    if ( !status.getSuccess()) {
+                        Log.getLogger(Launcher.class).warn(status.getMessage());
+                    }
+                } else {
+                    Log.getLogger(Launcher.class).warn("Invalid uid or gid (must satisfy 0 < id < 65536)");
+                }
+            } catch (NumberFormatException e) {
+                Log.getLogger(Launcher.class).warn("Invalid gigi.uid or gigi.gid", e);
             }
         }
     }