[lxc-devel] [PATCH 1/3] lxc-attach: Try really hard to determine login shell
Serge Hallyn
serge.hallyn at ubuntu.com
Wed Mar 6 20:14:07 UTC 2013
Quoting Christian Seiler (christian at iwakd.de):
> If no command is specified, and using getpwuid() to determine the login
> shell fails, try to spawn a process that executes the utility 'getent'.
> getpwuid() may fail because of incompatibilities between the NSS
> implementations on the host and in the container.
>
> Signed-off-by: Christian Seiler <christian at iwakd.de>
Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>
One comment below - I'll just change it after applying yours if you
don't mind.
> ---
> src/lxc/attach.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++
> src/lxc/attach.h | 2 +
> src/lxc/lxc_attach.c | 18 +++++-
> 3 files changed, 172 insertions(+), 2 deletions(-)
>
> diff --git a/src/lxc/attach.c b/src/lxc/attach.c
> index af3d7a0..d1b3b0a 100644
> --- a/src/lxc/attach.c
> +++ b/src/lxc/attach.c
> @@ -32,7 +32,9 @@
> #include <sys/prctl.h>
> #include <sys/mount.h>
> #include <sys/syscall.h>
> +#include <sys/wait.h>
> #include <linux/unistd.h>
> +#include <pwd.h>
>
> #if !HAVE_DECL_PR_CAPBSET_DROP
> #define PR_CAPBSET_DROP 24
> @@ -275,3 +277,155 @@ int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
>
> return 0;
> }
> +
> +char *lxc_attach_getpwshell(uid_t uid)
> +{
> + /* local variables */
> + pid_t pid;
> + int pipes[2];
> + int ret;
> + int fd;
> + char *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);
> + if (ret < 0)
> + return NULL;
> +
> + pid = fork();
> + if (pid < 0) {
> + close(pipes[0]);
> + close(pipes[1]);
> + return NULL;
> + }
> +
> + if (pid) {
> + /* parent process */
> + FILE *pipe_f;
> + char *line = NULL;
> + size_t line_bufsz = 0;
> + int found = 0;
> + int status;
> +
> + close(pipes[1]);
> +
> + pipe_f = fdopen(pipes[0], "r");
> + while (getline(&line, &line_bufsz, pipe_f) != -1) {
> + char *token;
> + char *saveptr = NULL;
> + long value;
> + char *endptr = NULL;
> + int i;
> +
> + /* 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); 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;
If the sanity check below now fails, we ill leak result.
Not very important since we're about to exec, but I'll add
a if (result) free(result); right here.
> + result = strdup(token);
> +
> + /* sanity check that there are no fields after that */
> + token = strtok_r(NULL, ":", &saveptr);
> + if (token)
> + continue;
> +
> + found = 1;
> + }
More information about the lxc-devel
mailing list