From: Christian Brauner Date: Wed, 11 Jul 2018 21:12:04 +0000 (+0200) Subject: attach: simplify lxc_attach_getpwshell() X-Git-Tag: lxc-2.0.10~54 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b789a324dd26c8e42e6aa43be76f666711efcaf0;p=thirdparty%2Flxc.git attach: simplify lxc_attach_getpwshell() Signed-off-by: Christian Brauner --- diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 599fc5015..53deb0f40 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -441,12 +441,15 @@ static char *lxc_attach_getpwshell(uid_t uid) int fd, ret; pid_t pid; int pipes[2]; - char *result = NULL; + FILE *pipe_f; + bool found = false; + size_t line_bufsz = 0; + char *line = NULL, *result = NULL; /* We need to fork off a process that runs the getent program, and we * need to capture its output, so we use a pipe for that purpose. */ - ret = pipe(pipes); + ret = pipe2(pipes, O_CLOEXEC); if (ret < 0) return NULL; @@ -457,100 +460,7 @@ static char *lxc_attach_getpwshell(uid_t uid) return NULL; } - if (pid) { - int status; - FILE *pipe_f; - int found = 0; - size_t line_bufsz = 0; - char *line = NULL; - - close(pipes[1]); - - pipe_f = fdopen(pipes[0], "r"); - while (getline(&line, &line_bufsz, pipe_f) != -1) { - int i; - long value; - char *token; - char *endptr = NULL, *saveptr = NULL; - - /* If we already found something, just continue to read - * until the pipe doesn't deliver any more data, but - * don't modify the existing data structure. - */ - if (found) - continue; - - /* Trim line on the right hand side. */ - for (i = strlen(line); i > 0 && (line[i - 1] == '\n' || line[i - 1] == '\r'); --i) - line[i - 1] = '\0'; - - /* Split into tokens: first: user name. */ - token = strtok_r(line, ":", &saveptr); - if (!token) - continue; - /* next: dummy password field */ - token = strtok_r(NULL, ":", &saveptr); - if (!token) - continue; - /* next: user id */ - token = strtok_r(NULL, ":", &saveptr); - value = token ? strtol(token, &endptr, 10) : 0; - if (!token || !endptr || *endptr || value == LONG_MIN || value == LONG_MAX) - continue; - /* dummy sanity check: user id matches */ - if ((uid_t) value != uid) - continue; - /* skip fields: gid, gecos, dir, go to next field 'shell' */ - for (i = 0; i < 4; i++) { - token = strtok_r(NULL, ":", &saveptr); - if (!token) - break; - } - if (!token) - continue; - free(result); - result = strdup(token); - - /* Sanity check that there are no fields after that. */ - token = strtok_r(NULL, ":", &saveptr); - if (token) - continue; - - found = 1; - } - - free(line); - fclose(pipe_f); - again: - if (waitpid(pid, &status, 0) < 0) { - if (errno == EINTR) - goto again; - free(result); - return NULL; - } - - /* Some sanity checks. If anything even hinted at going wrong, - * we can't be sure we have a valid result, so we assume we - * don't. - */ - - if (!WIFEXITED(status)) { - free(result); - return NULL; - } - - if (WEXITSTATUS(status) != 0) { - free(result); - return NULL; - } - - if (!found) { - free(result); - return NULL; - } - - return result; - } else { + if (!pid) { char uid_buf[32]; char *arguments[] = { "getent", @@ -562,31 +472,108 @@ static char *lxc_attach_getpwshell(uid_t uid) close(pipes[0]); /* We want to capture stdout. */ - dup2(pipes[1], 1); + ret = dup2(pipes[1], STDOUT_FILENO); close(pipes[1]); + if (ret < 0) + exit(EXIT_FAILURE); /* Get rid of stdin/stderr, so we try to associate it with * /dev/null. */ - fd = open("/dev/null", O_RDWR); + fd = open_devnull(); if (fd < 0) { - close(0); - close(2); + close(STDIN_FILENO); + close(STDERR_FILENO); } else { - dup2(fd, 0); - dup2(fd, 2); + (void)dup3(fd, STDIN_FILENO, O_CLOEXEC); + (void)dup3(fd, STDOUT_FILENO, O_CLOEXEC); close(fd); } /* Finish argument list. */ - ret = snprintf(uid_buf, sizeof(uid_buf), "%ld", (long) uid); - if (ret <= 0) - exit(-1); + ret = snprintf(uid_buf, sizeof(uid_buf), "%ld", (long)uid); + if (ret <= 0 || ret >= sizeof(uid_buf)) + exit(EXIT_FAILURE); /* Try to run getent program. */ - (void) execvp("getent", arguments); - exit(-1); + (void)execvp("getent", arguments); + exit(EXIT_FAILURE); } + + close(pipes[1]); + + pipe_f = fdopen(pipes[0], "r"); + while (getline(&line, &line_bufsz, pipe_f) != -1) { + int i; + long value; + char *token; + char *endptr = NULL, *saveptr = NULL; + + /* If we already found something, just continue to read + * until the pipe doesn't deliver any more data, but + * don't modify the existing data structure. + */ + if (found) + continue; + + /* Trim line on the right hand side. */ + for (i = strlen(line); i > 0 && (line[i - 1] == '\n' || line[i - 1] == '\r'); --i) + line[i - 1] = '\0'; + + /* Split into tokens: first: user name. */ + token = strtok_r(line, ":", &saveptr); + if (!token) + continue; + + /* next: dummy password field */ + token = strtok_r(NULL, ":", &saveptr); + if (!token) + continue; + + /* next: user id */ + token = strtok_r(NULL, ":", &saveptr); + value = token ? strtol(token, &endptr, 10) : 0; + if (!token || !endptr || *endptr || value == LONG_MIN || + value == LONG_MAX) + continue; + + /* dummy sanity check: user id matches */ + if ((uid_t)value != uid) + continue; + + /* skip fields: gid, gecos, dir, go to next field 'shell' */ + for (i = 0; i < 4; i++) { + token = strtok_r(NULL, ":", &saveptr); + if (!token) + continue; + } + if (!token) + continue; + free(result); + result = strdup(token); + + /* Sanity check that there are no fields after that. */ + token = strtok_r(NULL, ":", &saveptr); + if (token) + continue; + + found = true; + } + free(line); + fclose(pipe_f); + + ret = wait_for_pid(pid); + if (ret < 0) { + free(result); + return NULL; + } + + if (!found) { + free(result); + return NULL; + } + + return result; } static void lxc_attach_get_init_uidgid(uid_t *init_uid, gid_t *init_gid)