+static int write_uid_gid_map(pid_t child_pid, bool gidmap, int id)
+{
+ int map_file;
+ char map_path[64];
+ const char *map_format = "%d %d %d\n";
+ if (snprintf(map_path, sizeof(map_path), "/proc/%d/%s",
+ child_pid, gidmap?"gid_map":"uid_map") < 0)
+ return -1;
+
+ if ((map_file = open(map_path, O_WRONLY)) == -1)
+ return -1;
+
+ if (dprintf(map_file, map_format, 0, id, 1) == -1) {
+ close(map_file);
+ return -1;
+ }
+
+ close(map_file);
+ return 0;
+}
+
+static int write_setgroups(pid_t child_pid, bool allow)
+{
+ int setgroups_file;
+ char setgroups_path[64];
+
+ if (snprintf(setgroups_path, sizeof(setgroups_path), "/proc/%d/setgroups",
+ child_pid) < 0) {
+ return -1;
+ }
+
+ if ((setgroups_file = open(setgroups_path, O_WRONLY)) == -1) {
+ return -1;
+ }
+
+ if (dprintf(setgroups_file, allow?"allow":"deny") == -1) {
+ close(setgroups_file);
+ return -1;
+ }
+
+ close(setgroups_file);
+ return 0;
+}
+
+static void get_jail_user(int *user, int *user_gid, int *gr_gid)
+{
+ struct passwd *p = NULL;
+ struct group *g = NULL;
+
+ if (opts.user) {
+ p = getpwnam(opts.user);
+ if (!p) {
+ ERROR("failed to get uid/gid for user %s: %d (%s)\n",
+ opts.user, errno, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ *user = p->pw_uid;
+ *user_gid = p->pw_gid;
+ } else {
+ *user = -1;
+ *user_gid = -1;
+ }
+
+ if (opts.group) {
+ g = getgrnam(opts.group);
+ if (!g) {
+ ERROR("failed to get gid for group %s: %m\n", opts.group);
+ exit(EXIT_FAILURE);
+ }
+ *gr_gid = g->gr_gid;
+ } else {
+ *gr_gid = -1;
+ }
+};
+
+static void set_jail_user(int pw_uid, int user_gid, int gr_gid)
+{
+ if ((user_gid != -1) && initgroups(opts.user, user_gid)) {
+ ERROR("failed to initgroups() for user %s: %m\n", opts.user);
+ exit(EXIT_FAILURE);
+ }
+
+ if ((gr_gid != -1) && setregid(gr_gid, gr_gid)) {
+ ERROR("failed to set group id %d: %m\n", gr_gid);
+ exit(EXIT_FAILURE);
+ }
+
+ if ((pw_uid != -1) && setreuid(pw_uid, pw_uid)) {
+ ERROR("failed to set user id %d: %m\n", pw_uid);
+ exit(EXIT_FAILURE);
+ }
+}
+