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;
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",
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)