attach: simplify lxc_attach_getpwshell()

parent ba7bd8c8
......@@ -448,12 +448,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;
......@@ -464,100 +467,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",
......@@ -569,31 +479,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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment