Skip to content
Snippets Groups Projects
Commit 600c0cd8 authored by Martin Mareš's avatar Martin Mareš
Browse files

Wrapper: Fix array sizes

parent 2d26e579
No related branches found
No related tags found
No related merge requests found
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#define NONRET __attribute__((noreturn)) #define NONRET __attribute__((noreturn))
#define UNUSED __attribute__((unused)) #define UNUSED __attribute__((unused))
#define ARRAY_SIZE(a) (int)(sizeof(a) / sizeof(*(a)))
static void NONRET die(const char *fmt, ...) static void NONRET die(const char *fmt, ...)
{ {
...@@ -93,6 +94,8 @@ static void get_credentials(void) ...@@ -93,6 +94,8 @@ static void get_credentials(void)
if (glen >= (int) sizeof(as_groups)) if (glen >= (int) sizeof(as_groups))
die("Group list too long"); die("Group list too long");
} }
free(groups);
} }
static void switch_ugid(void) static void switch_ugid(void)
...@@ -104,21 +107,10 @@ static void switch_ugid(void) ...@@ -104,21 +107,10 @@ static void switch_ugid(void)
die("Failed to set user id: %m"); die("Failed to set user id: %m");
} }
int main(int argc UNUSED, char **argv UNUSED) static char **make_args(int argc, char **argv)
{ {
sanitize_fds();
umask(0077);
if (geteuid())
die("Must be run setuid");
get_credentials();
switch_ugid();
char *program = DESTDIR "/usr/bin/shipcat";
char **args = xmalloc(sizeof(char *) * (5 + argc)); char **args = xmalloc(sizeof(char *) * (5 + argc));
args[0] = program; args[0] = DESTDIR "/usr/bin/shipcat";
args[1] = "--as-user"; args[1] = "--as-user";
args[2] = as_user; args[2] = as_user;
args[3] = "--as-groups"; args[3] = "--as-groups";
...@@ -126,14 +118,60 @@ int main(int argc UNUSED, char **argv UNUSED) ...@@ -126,14 +118,60 @@ int main(int argc UNUSED, char **argv UNUSED)
for (int i=1; i<argc; i++) for (int i=1; i<argc; i++)
args[4+i] = argv[i]; args[4+i] = argv[i];
args[4+argc] = NULL; args[4+argc] = NULL;
return args;
}
char * const env[] = { static char **make_env(void)
{
static char *set_env[] = {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
NULL
}; };
if (execve(program, args, env) < 0) static char *inherit_env[] = {
die("Cannot execute %s: %m", program); "TERM=",
};
char **env = xmalloc(sizeof(char *) * (ARRAY_SIZE(set_env) + ARRAY_SIZE(inherit_env) + 1));
char **ep = env;
for (int i=0; i < ARRAY_SIZE(set_env); i++)
*ep++ = set_env[i];
for (int i=0; environ[i]; i++)
{
char *e = environ[i];
int elen = strlen(e);
for (int j=0; j < ARRAY_SIZE(inherit_env); j++)
{
char *p = inherit_env[j];
int plen = strlen(p);
if (elen >= plen && !memcmp(e, p, plen))
{
*ep++ = e;
break;
}
}
}
*ep = NULL;
return env;
}
int main(int argc, char **argv)
{
sanitize_fds();
umask(0077);
if (geteuid())
die("Must be run setuid");
get_credentials();
switch_ugid();
char **args = make_args(argc, argv);
char **env = make_env();
if (execve(args[0], args, env) < 0)
die("Cannot execute %s: %m", args[0]);
die("This must never happen"); die("This must never happen");
} }
...@@ -15,6 +15,7 @@ sys.path.append('/tmp/shc/usr/lib/python') ...@@ -15,6 +15,7 @@ sys.path.append('/tmp/shc/usr/lib/python')
from shipcat.config import GlobalConfig, ContainerConfig, ConfigError from shipcat.config import GlobalConfig, ContainerConfig, ConfigError
def die(msg: str) -> NoReturn: def die(msg: str) -> NoReturn:
print(msg, file=sys.stderr) print(msg, file=sys.stderr)
sys.exit(1) sys.exit(1)
...@@ -24,6 +25,21 @@ def progress(msg: str) -> None: ...@@ -24,6 +25,21 @@ def progress(msg: str) -> None:
print(msg, file=sys.stderr, end="", flush=True) print(msg, file=sys.stderr, end="", flush=True)
def run_command(args: List[str], *rest, **kwargs) -> None:
res = subprocess.run(args, *rest, **kwargs)
if res.returncode != 0:
die('Command failed: ' + " ".join(args))
def load_config() -> GlobalConfig:
try:
# FIXME: Path to config
return GlobalConfig.load('shipcat.toml')
except ConfigError as e:
print(e, file=sys.stderr)
sys.exit(1)
def setup_container(args: argparse.Namespace, require_root: bool) -> ContainerConfig: def setup_container(args: argparse.Namespace, require_root: bool) -> ContainerConfig:
if os.geteuid() != 0: if os.geteuid() != 0:
die('This program must be run setuid root') die('This program must be run setuid root')
...@@ -104,7 +120,7 @@ class SubIds: ...@@ -104,7 +120,7 @@ class SubIds:
return SubIdRange(i, size, user) return SubIdRange(i, size, user)
def do_init(args: argparse.Namespace) -> None: def cmd_init(args: argparse.Namespace) -> None:
name = args.name name = args.name
cc = setup_container(args, True) cc = setup_container(args, True)
...@@ -114,9 +130,8 @@ def do_init(args: argparse.Namespace) -> None: ...@@ -114,9 +130,8 @@ def do_init(args: argparse.Namespace) -> None:
progress('already exists\n') progress('already exists\n')
except KeyError: except KeyError:
progress('creating\n') progress('creating\n')
subprocess.run( run_command(
['adduser', '--system', '--group', '--gecos', f'Container {name}', '--disabled-password', cc.user_name], ['adduser', '--system', '--group', '--gecos', f'Container {name}', '--disabled-password', cc.user_name],
check=True,
) )
pwd = getpwnam(cc.user_name) pwd = getpwnam(cc.user_name)
uid = pwd.pw_uid uid = pwd.pw_uid
...@@ -129,9 +144,8 @@ def do_init(args: argparse.Namespace) -> None: ...@@ -129,9 +144,8 @@ def do_init(args: argparse.Namespace) -> None:
else: else:
progress('allocating\n') progress('allocating\n')
sur = subuids.alloc_range(cc.user_name, 65536) sur = subuids.alloc_range(cc.user_name, 65536)
subprocess.run( run_command(
['usermod', '--add-subuids', f'{sur.first}-{sur.first + sur.count - 1}', cc.user_name], ['usermod', '--add-subuids', f'{sur.first}-{sur.first + sur.count - 1}', cc.user_name],
check=True,
) )
progress('Subgid range: ') progress('Subgid range: ')
...@@ -142,9 +156,8 @@ def do_init(args: argparse.Namespace) -> None: ...@@ -142,9 +156,8 @@ def do_init(args: argparse.Namespace) -> None:
else: else:
progress('allocating\n') progress('allocating\n')
sgr = subgids.alloc_range(cc.user_name, 65536) sgr = subgids.alloc_range(cc.user_name, 65536)
subprocess.run( run_command(
['usermod', '--add-subgids', f'{sgr.first}-{sgr.first + sgr.count - 1}', cc.user_name], ['usermod', '--add-subgids', f'{sgr.first}-{sgr.first + sgr.count - 1}', cc.user_name],
check=True,
) )
progress(f'Using user {cc.user_name}, uid {uid}, subuids {sur.first}+{sur.count}, subgids {sgr.first}+{sgr.count}\n') progress(f'Using user {cc.user_name}, uid {uid}, subuids {sur.first}+{sur.count}, subgids {sgr.first}+{sgr.count}\n')
...@@ -175,26 +188,30 @@ def do_init(args: argparse.Namespace) -> None: ...@@ -175,26 +188,30 @@ def do_init(args: argparse.Namespace) -> None:
progress(f'{ip}\n') progress(f'{ip}\n')
def do_create(args: argparse.Namespace) -> None: def service_action(cc: ContainerConfig, action: str) -> None:
run_command(
['systemctl', action, f'shc@{cc.container}.service'],
)
def cmd_create(args: argparse.Namespace) -> None:
name = args.name name = args.name
cc = setup_container(args, False) cc = setup_container(args, False)
data_dir = Path(cc.root_dir) / 'data' data_dir = Path(cc.root_dir) / 'data'
ip = socket.gethostbyname(name) ip = socket.gethostbyname(name)
subprocess.run( run_command(
['podman', 'pull', cc.image], ['podman', 'pull', cc.image],
check=True,
) )
# FIXME: If the container was running, stop it service_action(cc, 'stop')
subprocess.run( run_command(
['podman', 'rm', '-if', name], ['podman', 'rm', '-if', name],
check=True,
) )
subprocess.run( run_command(
[ [
'podman', 'create', 'podman', 'create',
'--name', name, '--name', name,
...@@ -208,12 +225,22 @@ def do_create(args: argparse.Namespace) -> None: ...@@ -208,12 +225,22 @@ def do_create(args: argparse.Namespace) -> None:
'--subgidname', cc.user_name, '--subgidname', cc.user_name,
cc.image, cc.image,
], ],
check=True,
) )
def do_start(args: argparse.Namespace) -> None: def cmd_start(args: argparse.Namespace) -> None:
pass cc = setup_container(args, False)
service_action(cc, 'start')
def cmd_stop(args: argparse.Namespace) -> None:
cc = setup_container(args, False)
service_action(cc, 'stop')
def cmd_status(args: argparse.Namespace) -> None:
cc = setup_container(args, False)
service_action(cc, 'status')
def parse_int_list(s: str) -> List[int]: def parse_int_list(s: str) -> List[int]:
...@@ -236,17 +263,21 @@ create_parser.add_argument('name', help='name of the container') ...@@ -236,17 +263,21 @@ create_parser.add_argument('name', help='name of the container')
start_parser = subparsers.add_parser('start', help='start a container', description='Start a container') start_parser = subparsers.add_parser('start', help='start a container', description='Start a container')
start_parser.add_argument('name', help='name of the container') start_parser.add_argument('name', help='name of the container')
status_parser = subparsers.add_parser('status', help='show container status', description='Show container status')
status_parser.add_argument('name', help='name of the container')
stop_parser = subparsers.add_parser('stop', help='stop a container', description='Stop a container')
stop_parser.add_argument('name', help='name of the container')
args = parser.parse_args() args = parser.parse_args()
try: actions = {
config = GlobalConfig.load('shipcat.toml') 'create': cmd_create,
except ConfigError as e: 'init': cmd_init,
print(e, file=sys.stderr) 'start': cmd_start,
sys.exit(1) 'status': cmd_status,
'stop': cmd_stop,
}
if args.action == 'init': config = load_config()
do_init(args) actions[args.action](args)
elif args.action == 'create':
do_create(args)
elif args.action == 'start':
do_start(args)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment