From a59b5c1709ac6fd9b5be043119425338576e9bc7 Mon Sep 17 00:00:00 2001 From: Lucas Werkmeister Date: Wed, 7 Sep 2016 15:03:47 +0200 Subject: [PATCH] add: support configuring SetUID behavior MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - 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 | 37 ++++++++++++++++++++---- src/org/cacert/gigi/Launcher.java | 20 +++++++++++-- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/natives/org_cacert_gigi_natives_SetUID.c b/natives/org_cacert_gigi_natives_SetUID.c index 6c94d619..1b2350b4 100644 --- a/natives/org_cacert_gigi_natives_SetUID.c +++ b/natives/org_cacert_gigi_natives_SetUID.c @@ -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 diff --git a/src/org/cacert/gigi/Launcher.java b/src/org/cacert/gigi/Launcher.java index 5f767a63..7c588d8e 100644 --- a/src/org/cacert/gigi/Launcher.java +++ b/src/org/cacert/gigi/Launcher.java @@ -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); } } } -- 2.39.2