Rewrite uid mapping system

This commit is contained in:
Robert Swiecki 2017-05-26 23:07:47 +02:00
parent a2a497f089
commit 4eaa6cc9d3
7 changed files with 238 additions and 173 deletions

View File

@ -102,7 +102,7 @@ indent:
# DO NOT DELETE THIS LINE -- make depend depends on it. # DO NOT DELETE THIS LINE -- make depend depends on it.
nsjail.o: nsjail.h common.h cmdline.h log.h net.h subproc.h nsjail.o: nsjail.h common.h cmdline.h log.h net.h subproc.h
cmdline.o: cmdline.h common.h config.h log.h mount.h util.h cmdline.o: cmdline.h common.h config.h log.h mount.h util.h user.h
config.o: common.h config.h log.h util.h config.o: common.h config.h log.h util.h
contain.o: contain.h common.h cgroup.h log.h mount.h net.h pid.h user.h contain.o: contain.h common.h cgroup.h log.h mount.h net.h pid.h user.h
contain.o: util.h uts.h contain.o: util.h uts.h

224
cmdline.c
View File

@ -45,6 +45,7 @@
#include "log.h" #include "log.h"
#include "mount.h" #include "mount.h"
#include "util.h" #include "util.h"
#include "user.h"
struct custom_option { struct custom_option {
struct option opt; struct option opt;
@ -67,8 +68,8 @@ struct custom_option custom_opts[] = {
{{"config", required_argument, NULL, 'C'}, "Configuration file in the config.proto ProtoBuf format"}, {{"config", required_argument, NULL, 'C'}, "Configuration file in the config.proto ProtoBuf format"},
{{"chroot", required_argument, NULL, 'c'}, "Directory containing / of the jail (default: none)"}, {{"chroot", required_argument, NULL, 'c'}, "Directory containing / of the jail (default: none)"},
{{"rw", no_argument, NULL, 0x601}, "Mount / and /proc as RW (default: RO)"}, {{"rw", no_argument, NULL, 0x601}, "Mount / and /proc as RW (default: RO)"},
{{"user", required_argument, NULL, 'u'}, "Username/uid of processess inside the jail (default: your current uid). You can also use inside_ns_uid:outside_ns_uid convention here. Can be specified multiple times"}, {{"user", required_argument, NULL, 'u'}, "Username/uid of processess inside the jail (default: your current uid). You can also use inside_ns_uid:outside_ns_uid:count convention here. Can be specified multiple times"},
{{"group", required_argument, NULL, 'g'}, "Groupname/gid of processess inside the jail (default: your current gid). You can also use inside_ns_gid:global_ns_gid convention here. Can be specified multiple times"}, {{"group", required_argument, NULL, 'g'}, "Groupname/gid of processess inside the jail (default: your current gid). You can also use inside_ns_gid:global_ns_gid:count convention here. Can be specified multiple times"},
{{"hostname", required_argument, NULL, 'H'}, "UTS name (hostname) of the jail (default: 'NSJAIL')"}, {{"hostname", required_argument, NULL, 'H'}, "UTS name (hostname) of the jail (default: 'NSJAIL')"},
{{"cwd", required_argument, NULL, 'D'}, "Directory in the namespace the process will run (default: '/')"}, {{"cwd", required_argument, NULL, 'D'}, "Directory in the namespace the process will run (default: '/')"},
{{"port", required_argument, NULL, 'p'}, "TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0)"}, {{"port", required_argument, NULL, 'p'}, "TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0)"},
@ -233,13 +234,15 @@ void cmdlineLogParams(struct nsjconf_t *nsjconf)
{ {
struct idmap_t *p; struct idmap_t *p;
TAILQ_FOREACH(p, &nsjconf->uids, pointers) { TAILQ_FOREACH(p, &nsjconf->uids, pointers) {
LOG_I("Uid map: inside_uid:%d outside_uid:%d", p->inside_id, p->outside_id); LOG_I("Uid map: inside_uid:%d outside_uid:%d count:%zu", p->inside_id,
p->outside_id, p->count);
if (p->outside_id == 0) { if (p->outside_id == 0) {
LOG_W("Process will be UID/EUID=0 in the global user namespace"); LOG_W("Process will be UID/EUID=0 in the global user namespace");
} }
} }
TAILQ_FOREACH(p, &nsjconf->gids, pointers) { TAILQ_FOREACH(p, &nsjconf->gids, pointers) {
LOG_I("Gid map: inside_gid:%d outside_gid:%d", p->inside_id, p->outside_id); LOG_I("Gid map: inside_gid:%d outside_gid:%d count:%zu", p->inside_id,
p->outside_id, p->count);
if (p->outside_id == 0) { if (p->outside_id == 0) {
LOG_W("Process will be GID/EGID=0 in the global user namespace"); LOG_W("Process will be GID/EGID=0 in the global user namespace");
} }
@ -247,17 +250,17 @@ void cmdlineLogParams(struct nsjconf_t *nsjconf)
} }
{ {
struct mapping_t *p; struct idmap_t *p;
TAILQ_FOREACH(p, &nsjconf->uid_mappings, pointers) { TAILQ_FOREACH(p, &nsjconf->uid_newuidmap, pointers) {
LOG_I("Newuid mapping: inside_uid:'%s' outside_uid:'%s' count:'%s'", LOG_I("Newuid mapping: inside_uid:%u outside_uid:%u count:%zu",
p->inside_id, p->outside_id, p->count); p->inside_id, p->outside_id, p->count);
if (p->outside_id == 0) { if (p->outside_id == 0) {
LOG_W("Process will be UID/EUID=0 in the global user namespace"); LOG_W("Process will be UID/EUID=0 in the global user namespace");
} }
} }
TAILQ_FOREACH(p, &nsjconf->gid_mappings, pointers) { TAILQ_FOREACH(p, &nsjconf->gid_newuidmap, pointers) {
LOG_I("Newgid mapping: inside_uid:'%s' outside_uid:'%s' count:'%s'", LOG_I("Newgid mapping: inside_uid:%u outside_uid:%u count:%zu",
p->inside_id, p->outside_id, p->count); p->inside_id, p->outside_id, p->count);
if (p->outside_id == 0) { if (p->outside_id == 0) {
LOG_W("Process will be GID/EGID=0 in the global user namespace"); LOG_W("Process will be GID/EGID=0 in the global user namespace");
@ -266,16 +269,6 @@ void cmdlineLogParams(struct nsjconf_t *nsjconf)
} }
} }
static bool cmdlineIsANumber(const char *s)
{
for (int i = 0; s[i]; s++) {
if (!isdigit(s[i]) && s[i] != 'x') {
return false;
}
}
return true;
}
__rlim64_t cmdlineParseRLimit(int res, const char *optarg, unsigned long mul) __rlim64_t cmdlineParseRLimit(int res, const char *optarg, unsigned long mul)
{ {
struct rlimit64 cur; struct rlimit64 cur;
@ -288,7 +281,7 @@ __rlim64_t cmdlineParseRLimit(int res, const char *optarg, unsigned long mul)
if (strcasecmp(optarg, "def") == 0) { if (strcasecmp(optarg, "def") == 0) {
return cur.rlim_cur; return cur.rlim_cur;
} }
if (cmdlineIsANumber(optarg) == false) { if (utilIsANumber(optarg) == false) {
LOG_F("RLIMIT %d needs a numeric or 'max'/'def' value ('%s' provided)", res, LOG_F("RLIMIT %d needs a numeric or 'max'/'def' value ('%s' provided)", res,
optarg); optarg);
} }
@ -304,6 +297,10 @@ __rlim64_t cmdlineParseRLimit(int res, const char *optarg, unsigned long mul)
* string. */ * string. */
static char *cmdlineSplitStrByColon(char *spec) static char *cmdlineSplitStrByColon(char *spec)
{ {
if (spec == NULL) {
return NULL;
}
char *dest = spec; char *dest = spec;
while (*dest != ':' && *dest != '\0') { while (*dest != ':' && *dest != '\0') {
dest++; dest++;
@ -314,97 +311,13 @@ static char *cmdlineSplitStrByColon(char *spec)
*dest = '\0'; *dest = '\0';
return dest + 1; return dest + 1;
case '\0': case '\0':
return spec; return NULL;
default: default:
// not reached LOG_F("Impossible condition in cmdlineSplitStrByColon()");
return spec; return NULL;
} }
} }
static bool cmdlineParseUid(struct nsjconf_t *nsjconf, char *str)
{
if (str == NULL) {
return true;
}
char *second = cmdlineSplitStrByColon(str);
pid_t inside_uid;
pid_t outside_uid;
struct passwd *pw = getpwnam(str);
if (pw != NULL) {
inside_uid = pw->pw_uid;
} else if (cmdlineIsANumber(str)) {
inside_uid = (uid_t) strtoull(str, NULL, 0);
} else {
LOG_E("No such user '%s'", str);
return false;
}
if (str == second) {
outside_uid = getuid();
} else {
pw = getpwnam(second);
if (pw != NULL) {
outside_uid = pw->pw_uid;
} else if (cmdlineIsANumber(second)) {
outside_uid = (uid_t) strtoull(second, NULL, 0);
} else {
LOG_E("No such user '%s'", second);
return false;
}
}
struct idmap_t *p = utilMalloc(sizeof(struct idmap_t));
p->inside_id = inside_uid;
p->outside_id = outside_uid;
TAILQ_INSERT_TAIL(&nsjconf->uids, p, pointers);
return true;
}
static bool cmdlineParseGid(struct nsjconf_t *nsjconf, char *str)
{
if (str == NULL) {
return true;
}
char *second = cmdlineSplitStrByColon(str);
gid_t inside_gid;
gid_t outside_gid;
struct group *gr = getgrnam(str);
if (gr != NULL) {
inside_gid = gr->gr_gid;
} else if (cmdlineIsANumber(str)) {
inside_gid = (gid_t) strtoull(str, NULL, 0);
} else {
LOG_E("No such group '%s'", str);
return false;
}
if (str == second) {
outside_gid = getgid();
} else {
gr = getgrnam(second);
if (gr != NULL) {
outside_gid = gr->gr_gid;
} else if (cmdlineIsANumber(second)) {
outside_gid = (gid_t) strtoull(second, NULL, 0);
} else {
LOG_E("No such group '%s'", second);
return false;
}
}
struct idmap_t *p = utilMalloc(sizeof(struct idmap_t));
p->inside_id = inside_gid;
p->outside_id = outside_gid;
TAILQ_INSERT_TAIL(&nsjconf->gids, p, pointers);
return true;
}
bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf) bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
{ {
/* *INDENT-OFF* */ /* *INDENT-OFF* */
@ -460,14 +373,14 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */
TAILQ_INIT(&nsjconf->uids);
TAILQ_INIT(&nsjconf->gids);
TAILQ_INIT(&nsjconf->envs);
TAILQ_INIT(&nsjconf->pids); TAILQ_INIT(&nsjconf->pids);
TAILQ_INIT(&nsjconf->mountpts); TAILQ_INIT(&nsjconf->mountpts);
TAILQ_INIT(&nsjconf->open_fds); TAILQ_INIT(&nsjconf->open_fds);
TAILQ_INIT(&nsjconf->uid_mappings); TAILQ_INIT(&nsjconf->envs);
TAILQ_INIT(&nsjconf->gid_mappings); TAILQ_INIT(&nsjconf->uids);
TAILQ_INIT(&nsjconf->gids);
TAILQ_INIT(&nsjconf->uid_newuidmap);
TAILQ_INIT(&nsjconf->gid_newuidmap);
static char cmdlineTmpfsSz[PATH_MAX] = "size=4194304"; static char cmdlineTmpfsSz[PATH_MAX] = "size=4194304";
@ -528,16 +441,6 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
case 'i': case 'i':
nsjconf->max_conns_per_ip = strtoul(optarg, NULL, 0); nsjconf->max_conns_per_ip = strtoul(optarg, NULL, 0);
break; break;
case 'u':
if (cmdlineParseUid(nsjconf, optarg) == false) {
LOG_F("cmdlineParseUid('%s')", optarg);
}
break;
case 'g':
if (cmdlineParseGid(nsjconf, optarg) == false) {
LOG_F("cmdlineParseGid('%s')", optarg);
}
break;
case 'l': case 'l':
nsjconf->logfile = optarg; nsjconf->logfile = optarg;
if (logInitLogFile(nsjconf) == false) { if (logInitLogFile(nsjconf) == false) {
@ -663,17 +566,72 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
p->val = optarg; p->val = optarg;
TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers); TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers);
} break; } break;
case 'U': case 'u':{
case 'G':{ char *i_id = optarg;
struct mapping_t *p = utilMalloc(sizeof(struct mapping_t)); char *o_id = cmdlineSplitStrByColon(i_id);
p->inside_id = optarg; char *cnt = cmdlineSplitStrByColon(o_id);
char *outside_id = cmdlineSplitStrByColon(optarg); size_t count = (cnt == NULL
p->outside_id = outside_id; || strlen(cnt) == 0) ? 1U : (size_t) strtoull(cnt,
p->count = cmdlineSplitStrByColon(outside_id); NULL,
if (c == 'U') { 0);
TAILQ_INSERT_TAIL(&nsjconf->uid_mappings, p, pointers);
struct idmap_t *p =
userParseId(i_id, o_id, count, false /* is_gid */ );
if (p) {
TAILQ_INSERT_TAIL(&nsjconf->uids, p, pointers);
} else { } else {
TAILQ_INSERT_TAIL(&nsjconf->gid_mappings, p, pointers); return false;
}
}
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);
struct idmap_t *p =
userParseId(i_id, o_id, count, true /* is_gid */ );
if (p) {
TAILQ_INSERT_TAIL(&nsjconf->gids, p, pointers);
} else {
return false;
}
}
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);
struct idmap_t *p =
userParseId(i_id, o_id, count, false /* is_gid */ );
if (p) {
TAILQ_INSERT_TAIL(&nsjconf->uid_newuidmap, p, pointers);
} else {
return false;
}
}
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);
struct idmap_t *p =
userParseId(i_id, o_id, count, true /* is_gid */ );
if (p) {
TAILQ_INSERT_TAIL(&nsjconf->gid_newuidmap, p, pointers);
} else {
return false;
} }
} }
break; break;
@ -822,12 +780,14 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
struct idmap_t *p = utilMalloc(sizeof(struct idmap_t)); struct idmap_t *p = utilMalloc(sizeof(struct idmap_t));
p->inside_id = getuid(); p->inside_id = getuid();
p->outside_id = getuid(); p->outside_id = getuid();
p->count = 1U;
TAILQ_INSERT_HEAD(&nsjconf->uids, p, pointers); TAILQ_INSERT_HEAD(&nsjconf->uids, p, pointers);
} }
if (TAILQ_EMPTY(&nsjconf->gids)) { if (TAILQ_EMPTY(&nsjconf->gids)) {
struct idmap_t *p = utilMalloc(sizeof(struct idmap_t)); struct idmap_t *p = utilMalloc(sizeof(struct idmap_t));
p->inside_id = getgid(); p->inside_id = getgid();
p->outside_id = getgid(); p->outside_id = getgid();
p->count = 1U;
TAILQ_INSERT_HEAD(&nsjconf->gids, p, pointers); TAILQ_INSERT_HEAD(&nsjconf->gids, p, pointers);
} }

View File

@ -74,16 +74,10 @@ struct mounts_t {
TAILQ_ENTRY(mounts_t) pointers; TAILQ_ENTRY(mounts_t) pointers;
}; };
struct mapping_t {
const char *inside_id;
const char *outside_id;
const char *count;
TAILQ_ENTRY(mapping_t) pointers;
};
struct idmap_t { struct idmap_t {
uid_t inside_id; uid_t inside_id;
uid_t outside_id; uid_t outside_id;
size_t count;
TAILQ_ENTRY(idmap_t) pointers; TAILQ_ENTRY(idmap_t) pointers;
}; };
@ -164,14 +158,14 @@ struct nsjconf_t {
size_t cgroup_pids_max; size_t cgroup_pids_max;
FILE *kafel_file; FILE *kafel_file;
char *kafel_string; char *kafel_string;
TAILQ_HEAD(uidlist, idmap_t) uids; TAILQ_HEAD(udmaplist, idmap_t) uids;
TAILQ_HEAD(gidlist, idmap_t) gids; TAILQ_HEAD(gdmaplist, idmap_t) gids;
TAILQ_HEAD(newuidmaplist, idmap_t) uid_newuidmap;
TAILQ_HEAD(newgidmaplist, idmap_t) gid_newuidmap;
TAILQ_HEAD(envlist, charptr_t) envs; TAILQ_HEAD(envlist, charptr_t) envs;
TAILQ_HEAD(pidslist, pids_t) pids; TAILQ_HEAD(pidslist, pids_t) pids;
TAILQ_HEAD(mountptslist, mounts_t) mountpts; TAILQ_HEAD(mountptslist, mounts_t) mountpts;
TAILQ_HEAD(fdslistt, fds_t) open_fds; TAILQ_HEAD(fdslistt, fds_t) open_fds;
TAILQ_HEAD(uidmaplistt, mapping_t) uid_mappings;
TAILQ_HEAD(gidmaplistt, mapping_t) gid_mappings;
}; };
#endif /* NS_COMMON_H */ #endif /* NS_COMMON_H */

154
user.c
View File

@ -24,12 +24,14 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <grp.h> #include <grp.h>
#include <pwd.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "log.h" #include "log.h"
@ -65,8 +67,8 @@ static bool userUidMapSelf(struct nsjconf_t *nsjconf, pid_t pid)
struct idmap_t *p; struct idmap_t *p;
TAILQ_FOREACH(p, &nsjconf->uids, pointers) { TAILQ_FOREACH(p, &nsjconf->uids, pointers) {
utilSSnPrintf(map, sizeof(map), "%lu %lu 1\n", (unsigned long)p->inside_id, utilSSnPrintf(map, sizeof(map), "%lu %lu %zu\n", (unsigned long)p->inside_id,
(unsigned long)p->outside_id); (unsigned long)p->outside_id, p->count);
} }
LOG_D("Writing '%s' to '%s'", map, fname); LOG_D("Writing '%s' to '%s'", map, fname);
@ -87,8 +89,8 @@ static bool userGidMapSelf(struct nsjconf_t *nsjconf, pid_t pid)
struct idmap_t *p; struct idmap_t *p;
TAILQ_FOREACH(p, &nsjconf->gids, pointers) { TAILQ_FOREACH(p, &nsjconf->gids, pointers) {
utilSSnPrintf(map, sizeof(map), "%lu %lu 1\n", (unsigned long)p->inside_id, utilSSnPrintf(map, sizeof(map), "%lu %lu %zu\n", (unsigned long)p->inside_id,
(unsigned long)p->outside_id); (unsigned long)p->outside_id, p->count);
} }
LOG_D("Writing '%s' to '%s'", map, fname); LOG_D("Writing '%s' to '%s'", map, fname);
@ -103,23 +105,38 @@ static bool userGidMapSelf(struct nsjconf_t *nsjconf, pid_t pid)
/* Use /usr/bin/newgidmap for writing the gid map */ /* Use /usr/bin/newgidmap for writing the gid map */
static bool userGidMapExternal(struct nsjconf_t *nsjconf, pid_t pid UNUSED) static bool userGidMapExternal(struct nsjconf_t *nsjconf, pid_t pid UNUSED)
{ {
char pid_str[128]; static size_t idx = 0;
snprintf(pid_str, sizeof(pid_str), "%d", (int)pid);
const char *argv[1024] = { "/usr/bin/newgidmap", pid_str };
size_t argv_idx = 2;
struct mapping_t *p; const char *argv[1024];
TAILQ_FOREACH(p, &nsjconf->gid_mappings, pointers) { char parms[1024][256];
if (argv_idx >= ARRAYSIZE(argv)) {
argv[idx++] = "/usr/bin/newgidmap";
snprintf(parms[idx], sizeof(parms[idx]), "%u", (unsigned)pid);
argv[idx] = parms[idx];
idx++;
struct idmap_t *p;
TAILQ_FOREACH(p, &nsjconf->gid_newuidmap, pointers) {
if ((idx + 4) >= ARRAYSIZE(argv)) {
LOG_W("Number of arguments to '/usr/bin/newgidmap' too big"); LOG_W("Number of arguments to '/usr/bin/newgidmap' too big");
return false; return false;
} }
argv[argv_idx++] = p->inside_id; snprintf(parms[idx], sizeof(parms[idx]), "%u", (unsigned)p->inside_id);
argv[argv_idx++] = p->outside_id; argv[idx] = parms[idx];
argv[argv_idx++] = p->count; idx++;
snprintf(parms[idx], sizeof(parms[idx]), "%u", (unsigned)p->outside_id);
argv[idx] = parms[idx];
idx++;
snprintf(parms[idx], sizeof(parms[idx]), "%zu", p->count);
argv[idx] = parms[idx];
idx++;
} }
argv[argv_idx++] = NULL;
argv[idx] = NULL;
if (subprocSystem(argv, environ) != 0) { if (subprocSystem(argv, environ) != 0) {
LOG_E("'/usr/bin/newgidmap' failed"); LOG_E("'/usr/bin/newgidmap' failed");
@ -132,23 +149,38 @@ static bool userGidMapExternal(struct nsjconf_t *nsjconf, pid_t pid UNUSED)
/* Use /usr/bin/newuidmap for writing the uid map */ /* Use /usr/bin/newuidmap for writing the uid map */
static bool userUidMapExternal(struct nsjconf_t *nsjconf, pid_t pid UNUSED) static bool userUidMapExternal(struct nsjconf_t *nsjconf, pid_t pid UNUSED)
{ {
char pid_str[128]; static size_t idx = 0;
snprintf(pid_str, sizeof(pid_str), "%d", (int)pid);
const char *argv[1024] = { "/usr/bin/newuidmap", pid_str };
size_t argv_idx = 2;
struct mapping_t *p; const char *argv[1024];
TAILQ_FOREACH(p, &nsjconf->uid_mappings, pointers) { char parms[1024][256];
if (argv_idx >= ARRAYSIZE(argv)) {
argv[idx++] = "/usr/bin/newuidmap";
snprintf(parms[idx], sizeof(parms[idx]), "%u", (unsigned)pid);
argv[idx] = parms[idx];
idx++;
struct idmap_t *p;
TAILQ_FOREACH(p, &nsjconf->uid_newuidmap, pointers) {
if ((idx + 4) >= ARRAYSIZE(argv)) {
LOG_W("Number of arguments to '/usr/bin/newuidmap' too big"); LOG_W("Number of arguments to '/usr/bin/newuidmap' too big");
return false; return false;
} }
argv[argv_idx++] = p->inside_id; snprintf(parms[idx], sizeof(parms[idx]), "%u", (unsigned)p->inside_id);
argv[argv_idx++] = p->outside_id; argv[idx] = parms[idx];
argv[argv_idx++] = p->count; idx++;
snprintf(parms[idx], sizeof(parms[idx]), "%u", (unsigned)p->outside_id);
argv[idx] = parms[idx];
idx++;
snprintf(parms[idx], sizeof(parms[idx]), "%zu", p->count);
argv[idx] = parms[idx];
idx++;
} }
argv[argv_idx++] = NULL;
argv[idx] = NULL;
if (subprocSystem(argv, environ) != 0) { if (subprocSystem(argv, environ) != 0) {
LOG_E("'/usr/bin/newuidmap' failed"); LOG_E("'/usr/bin/newuidmap' failed");
@ -160,7 +192,7 @@ static bool userUidMapExternal(struct nsjconf_t *nsjconf, pid_t pid UNUSED)
static bool userUidGidMap(struct nsjconf_t *nsjconf, pid_t pid) static bool userUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
{ {
if (TAILQ_EMPTY(&nsjconf->gid_mappings)) { if (TAILQ_EMPTY(&nsjconf->gid_newuidmap)) {
if (!userGidMapSelf(nsjconf, pid)) { if (!userGidMapSelf(nsjconf, pid)) {
return false; return false;
} }
@ -169,7 +201,7 @@ static bool userUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
return false; return false;
} }
} }
if (TAILQ_EMPTY(&nsjconf->uid_mappings)) { if (TAILQ_EMPTY(&nsjconf->gid_newuidmap)) {
return userUidMapSelf(nsjconf, pid); return userUidMapSelf(nsjconf, pid);
} else { } else {
return userUidMapExternal(nsjconf, pid); return userUidMapExternal(nsjconf, pid);
@ -221,3 +253,69 @@ bool userInitNsFromChild(struct nsjconf_t * nsjconf)
return true; return true;
} }
static uid_t cmdParseUid(const char *id)
{
if (id == NULL || strlen(id) == 0) {
return getuid();
}
struct passwd *pw = getpwnam(id);
if (pw != NULL) {
return pw->pw_uid;
}
if (utilIsANumber(id)) {
return (uid_t) strtoull(id, NULL, 0);
}
return -1;
}
static gid_t cmdParseGid(const char *id)
{
if (id == NULL || strlen(id) == 0) {
return getgid();
}
struct group *gr = getgrnam(id);
if (gr != NULL) {
return gr->gr_gid;
}
if (utilIsANumber(id)) {
return (gid_t) strtoull(id, NULL, 0);
}
return -1;
}
struct idmap_t *userParseId(const char *i_id, const char *o_id, size_t cnt, bool is_gid)
{
uid_t inside_id;
uid_t outside_id;
if (is_gid) {
inside_id = cmdParseGid(i_id);
if (inside_id == (uid_t) - 1) {
LOG_E("Cannot parse '%s' as GID", i_id);
return NULL;
}
outside_id = cmdParseGid(o_id);
if (inside_id == (uid_t) - 1) {
LOG_E("Cannot parse '%s' as GID", o_id);
return NULL;
}
} else {
inside_id = cmdParseUid(i_id);
if (inside_id == (uid_t) - 1) {
LOG_E("Cannot parse '%s' as UID", i_id);
return NULL;
}
outside_id = cmdParseUid(o_id);
if (inside_id == (uid_t) - 1) {
LOG_E("Cannot parse '%s' as UID", o_id);
return NULL;
}
}
struct idmap_t *p = utilMalloc(sizeof(struct idmap_t));
p->inside_id = inside_id;
p->outside_id = outside_id;
p->count = cnt;
return p;
}

3
user.h
View File

@ -27,7 +27,8 @@
#include "common.h" #include "common.h"
bool userInitNsFromParent(struct nsjconf_t *nsjconf, pid_t pid); bool userInitNsFromParent(struct nsjconf_t *nsjconf, pid_t pid);
bool userInitNsFromChild(struct nsjconf_t *nsjconf); bool userInitNsFromChild(struct nsjconf_t *nsjconf);
struct idmap_t *userParseId(const char *i_id, const char *o_id, size_t cnt, bool is_gid);
#endif /* NS_USER_H */ #endif /* NS_USER_H */

11
util.c
View File

@ -21,6 +21,7 @@
#include "util.h" #include "util.h"
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdarg.h> #include <stdarg.h>
@ -190,3 +191,13 @@ int utilSSnPrintf(char *str, size_t size, const char *format, ...)
return snprintf(str, size, "%s%s", buf1, buf2); return snprintf(str, size, "%s%s", buf1, buf2);
} }
bool utilIsANumber(const char *s)
{
for (int i = 0; s[i]; s++) {
if (!isdigit(s[i]) && s[i] != 'x') {
return false;
}
}
return true;
}

1
util.h
View File

@ -36,5 +36,6 @@ ssize_t utilWriteToFd(int fd, const void *buf, size_t len);
bool utilWriteBufToFile(const char *filename, const void *buf, size_t len, int open_flags); bool utilWriteBufToFile(const char *filename, const void *buf, size_t len, int open_flags);
bool utilCreateDirRecursively(const char *dir); bool utilCreateDirRecursively(const char *dir);
int utilSSnPrintf(char *str, size_t size, const char *format, ...); int utilSSnPrintf(char *str, size_t size, const char *format, ...);
bool utilIsANumber(const char *s);
#endif /* NS_UTIL_H */ #endif /* NS_UTIL_H */