diff --git a/cmdline.cc b/cmdline.cc index a97ea77..156fcbf 100644 --- a/cmdline.cc +++ b/cmdline.cc @@ -43,6 +43,8 @@ #include #include +#include +#include #include "caps.h" #include "config.h" @@ -293,29 +295,16 @@ uint64_t parseRLimit(int res, const char* optarg, unsigned long mul) { return val; } -/* findSpecDestination mutates spec (source:dest) to have a null byte instead - * of ':' in between source and dest, then returns a pointer to the dest - * string. */ -static char* cmdlineSplitStrByColon(char* spec) { - if (spec == NULL) { - return NULL; +static std::string argByColon(const char* str, size_t pos) { + if (!str) { + return ""; } - - char* dest = spec; - while (*dest != ':' && *dest != '\0') { - dest++; - } - - switch (*dest) { - case ':': - *dest = '\0'; - return dest + 1; - case '\0': - return NULL; - default: - LOG_F("Impossible condition in cmdlineSplitStrByColon()"); - return NULL; + std::vector vec; + util::strSplit(str, &vec, ':'); + if (pos > vec.size()) { + return ""; } + return vec[pos]; } std::unique_ptr parseArgs(int argc, char* argv[]) { @@ -568,66 +557,67 @@ std::unique_ptr parseArgs(int argc, char* argv[]) { nsjconf->envs.push_back(optarg); break; case 'u': { - char* i_id = optarg; - char* o_id = cmdlineSplitStrByColon(i_id); - char* cnt = cmdlineSplitStrByColon(o_id); - size_t count = - (cnt == NULL || strlen(cnt) == 0) ? 1U : (size_t)strtoull(cnt, NULL, 0); - if (user::parseId(nsjconf.get(), i_id, o_id, count, false /* is_gid */, - false /* is_newidmap */) == false) { + std::string i_id = argByColon(optarg, 0); + std::string o_id = argByColon(optarg, 1); + std::string cnt = argByColon(optarg, 2); + size_t count = std::strtoul(cnt.c_str(), nullptr, 0); + if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ false, + /* is_newidmap= */ false)) { return nullptr; } } break; case 'g': { - char* i_id = optarg; - char* o_id = cmdlineSplitStrByColon(i_id); - char* cnt = cmdlineSplitStrByColon(o_id); - size_t count = - (cnt == NULL || strlen(cnt) == 0) ? 1U : (size_t)strtoull(cnt, NULL, 0); - if (user::parseId(nsjconf.get(), i_id, o_id, count, true /* is_gid */, - false /* is_newidmap */) == false) { + std::string i_id = argByColon(optarg, 0); + std::string o_id = argByColon(optarg, 1); + std::string cnt = argByColon(optarg, 2); + size_t count = std::strtoul(cnt.c_str(), nullptr, 0); + if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ true, + /* is_newidmap= */ false)) { return nullptr; } } break; case 'U': { - char* i_id = optarg; - char* o_id = cmdlineSplitStrByColon(i_id); - char* cnt = cmdlineSplitStrByColon(o_id); - size_t count = - (cnt == NULL || strlen(cnt) == 0) ? 1U : (size_t)strtoull(cnt, NULL, 0); - if (user::parseId(nsjconf.get(), i_id, o_id, count, false /* is_gid */, - true /* is_newidmap */) == false) { + std::string i_id = argByColon(optarg, 0); + std::string o_id = argByColon(optarg, 1); + std::string cnt = argByColon(optarg, 2); + size_t count = std::strtoul(cnt.c_str(), nullptr, 0); + if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ false, + /* is_newidmap= */ true)) { return nullptr; } } break; case 'G': { - char* i_id = optarg; - char* o_id = cmdlineSplitStrByColon(i_id); - char* cnt = cmdlineSplitStrByColon(o_id); - size_t count = - (cnt == NULL || strlen(cnt) == 0) ? 1U : (size_t)strtoull(cnt, NULL, 0); - if (user::parseId(nsjconf.get(), i_id, o_id, count, true /* is_gid */, - true /* is_newidmap */) == false) { + std::string i_id = argByColon(optarg, 0); + std::string o_id = argByColon(optarg, 1); + std::string cnt = argByColon(optarg, 2); + size_t count = std::strtoul(cnt.c_str(), nullptr, 0); + if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ true, + /* is_newidmap= */ true)) { return nullptr; } } break; case 'R': { - const char* dst = cmdlineSplitStrByColon(optarg); - dst = dst ? dst : optarg; - if (!mnt::addMountPtTail(nsjconf.get(), /* src= */ optarg, dst, - /* fs_type= */ "", - /* options= */ "", MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY, + std::string src = argByColon(optarg, 0); + std::string dst = argByColon(optarg, 1); + if (dst.empty()) { + dst = src; + } + if (!mnt::addMountPtTail(nsjconf.get(), src.c_str(), dst.c_str(), + /* fs_type= */ "", /* options= */ "", + MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY, /* isDir= */ mnt::NS_DIR_MAYBE, /* mandatory= */ true, NULL, NULL, NULL, 0, /* is_symlink= */ false)) { return nullptr; } }; break; case 'B': { - const char* dst = cmdlineSplitStrByColon(optarg); - dst = dst ? dst : optarg; - if (!mnt::addMountPtTail(nsjconf.get(), /* src= */ optarg, dst, - /* fs_type= */ "", - /* options= */ "", MS_BIND | MS_REC | MS_PRIVATE, + std::string src = argByColon(optarg, 0); + std::string dst = argByColon(optarg, 1); + if (dst.empty()) { + dst = src; + } + if (!mnt::addMountPtTail(nsjconf.get(), src.c_str(), dst.c_str(), + /* fs_type= */ "", /* options= */ "", MS_BIND | MS_REC | MS_PRIVATE, /* isDir= */ mnt::NS_DIR_MAYBE, /* mandatory= */ true, NULL, NULL, NULL, 0, /* is_symlink= */ false)) { return nullptr; diff --git a/config.cc b/config.cc index 52d51b4..5abb1b0 100644 --- a/config.cc +++ b/config.cc @@ -45,8 +45,6 @@ namespace config { -#define VAL_IF_SET_OR_NULL(njc, val) (njc.has_##val() ? njc.val().c_str() : NULL) - static uint64_t configRLimit( int res, const nsjail::RLimit& rl, const uint64_t val, unsigned long mul = 1UL) { if (rl == nsjail::RLimit::VALUE) { @@ -186,16 +184,14 @@ static bool configParseInternal(nsjconf_t* nsjconf, const nsjail::NsJailConfig& nsjconf->clone_newcgroup = njc.clone_newcgroup(); for (ssize_t i = 0; i < njc.uidmap_size(); i++) { - if (!user::parseId(nsjconf, VAL_IF_SET_OR_NULL(njc.uidmap(i), inside_id), - VAL_IF_SET_OR_NULL(njc.uidmap(i), outside_id), njc.uidmap(i).count(), - false /* is_gid */, njc.uidmap(i).use_newidmap())) { + if (!user::parseId(nsjconf, njc.uidmap(i).inside_id(), njc.uidmap(i).outside_id(), + njc.uidmap(i).count(), false /* is_gid */, njc.uidmap(i).use_newidmap())) { return false; } } for (ssize_t i = 0; i < njc.gidmap_size(); i++) { - if (!user::parseId(nsjconf, VAL_IF_SET_OR_NULL(njc.gidmap(i), inside_id), - VAL_IF_SET_OR_NULL(njc.gidmap(i), outside_id), njc.gidmap(i).count(), - true /* is_gid */, njc.gidmap(i).use_newidmap())) { + if (!user::parseId(nsjconf, njc.gidmap(i).inside_id(), njc.gidmap(i).outside_id(), + njc.gidmap(i).count(), true /* is_gid */, njc.gidmap(i).use_newidmap())) { return false; } } diff --git a/user.cc b/user.cc index 827a7ec..d2e5064 100644 --- a/user.cc +++ b/user.cc @@ -265,59 +265,63 @@ bool initNsFromChild(nsjconf_t* nsjconf) { return true; } -static uid_t parseUid(const char* id) { - if (id == NULL || strlen(id) == 0) { +static uid_t parseUid(const std::string& id) { + if (id.empty()) { return getuid(); } - struct passwd* pw = getpwnam(id); + struct passwd* pw = getpwnam(id.c_str()); if (pw != NULL) { return pw->pw_uid; } - if (util::isANumber(id)) { - return (uid_t)strtoull(id, NULL, 0); + if (util::isANumber(id.c_str())) { + return (uid_t)strtoull(id.c_str(), NULL, 0); } return (uid_t)-1; } -static gid_t parseGid(const char* id) { - if (id == NULL || strlen(id) == 0) { +static gid_t parseGid(const std::string& id) { + if (id.empty()) { return getgid(); } - struct group* gr = getgrnam(id); + struct group* gr = getgrnam(id.c_str()); if (gr != NULL) { return gr->gr_gid; } - if (util::isANumber(id)) { - return (gid_t)strtoull(id, NULL, 0); + if (util::isANumber(id.c_str())) { + return (gid_t)strtoull(id.c_str(), NULL, 0); } return (gid_t)-1; } -bool parseId(nsjconf_t* nsjconf, const char* i_id, const char* o_id, size_t cnt, bool is_gid, - bool is_newidmap) { +bool parseId(nsjconf_t* nsjconf, const std::string& i_id, const std::string& o_id, size_t cnt, + bool is_gid, bool is_newidmap) { + if (cnt < 1) { + cnt = 1; + } + uid_t inside_id; uid_t outside_id; if (is_gid) { inside_id = parseGid(i_id); if (inside_id == (uid_t)-1) { - LOG_W("Cannot parse '%s' as GID", i_id); + LOG_W("Cannot parse '%s' as GID", i_id.c_str()); return false; } outside_id = parseGid(o_id); if (outside_id == (uid_t)-1) { - LOG_W("Cannot parse '%s' as GID", o_id); + LOG_W("Cannot parse '%s' as GID", o_id.c_str()); return false; } } else { inside_id = parseUid(i_id); if (inside_id == (uid_t)-1) { - LOG_W("Cannot parse '%s' as UID", i_id); + LOG_W("Cannot parse '%s' as UID", i_id.c_str()); return false; } outside_id = parseUid(o_id); if (outside_id == (uid_t)-1) { - LOG_W("Cannot parse '%s' as UID", o_id); + LOG_W("Cannot parse '%s' as UID", o_id.c_str()); return false; } } diff --git a/user.h b/user.h index 4e82397..598ea81 100644 --- a/user.h +++ b/user.h @@ -24,15 +24,16 @@ #include +#include + #include "nsjail.h" namespace user { bool initNsFromParent(nsjconf_t* nsjconf, pid_t pid); bool initNsFromChild(nsjconf_t* nsjconf); - -bool parseId(nsjconf_t* nsjconf, const char* i_id, const char* o_id, size_t cnt, bool is_gid, - bool is_newidmap); +bool parseId(nsjconf_t* nsjconf, const std::string& i_id, const std::string& o_id, size_t cnt, + bool is_gid, bool is_newidmap); } // namespace user diff --git a/util.cc b/util.cc index d295712..e48ea59 100644 --- a/util.cc +++ b/util.cc @@ -40,7 +40,9 @@ #include #include +#include #include +#include #include "logs.h" #include "macros.h" @@ -279,4 +281,12 @@ const std::string timeToStr(time_t t) { return timestr; } +void strSplit(const std::string str, std::vector* vec, char delim) { + std::string word; + std::istringstream stream(str); + for (std::string word; std::getline(stream, word, delim);) { + vec->push_back(word); + } +} + } // namespace util diff --git a/util.h b/util.h index 427e4a7..8b9a3cd 100644 --- a/util.h +++ b/util.h @@ -27,6 +27,7 @@ #include #include +#include #include "nsjail.h" @@ -42,6 +43,7 @@ bool isANumber(const char* s); uint64_t rnd64(void); const std::string sigName(int signo); const std::string timeToStr(time_t t); +void strSplit(const std::string str, std::vector* vec, char delim); } // namespace util