[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