[libvirt] [PATCH 11/17] virt-login-shell: honour the -c option to launch commands

John Ferlan jferlan at redhat.com
Wed Apr 27 18:28:33 UTC 2016



On 04/14/2016 11:22 AM, Daniel P. Berrange wrote:
> The virt-login-shell program is supposed to look like a
> regular shell to clients. Login services like sshd
> expect the shell to accept a '-c cmdstring' argument to
> specify a command to launch instead of presenting an
> interactive prompt.
> 
> We can implement this by simply passing the '-c cmdstring'
> data straight through to the real shell we use. This does
> not open any security holes, since the command is not run
> until we're inside the container namespaces. This allows
> scp to work for users with virt-login-shell.
> 
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
>  tools/virt-login-shell.c | 70 +++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 54 insertions(+), 16 deletions(-)
> 
> diff --git a/tools/virt-login-shell.c b/tools/virt-login-shell.c
> index ec759dc..34a8836 100644
> --- a/tools/virt-login-shell.c
> +++ b/tools/virt-login-shell.c
> @@ -100,20 +100,19 @@ static int virLoginShellAllowedUser(virConfPtr conf,
>      return ret;
>  }
>  
> -static char **virLoginShellGetShellArgv(virConfPtr conf)
> +static int virLoginShellGetShellArgv(virConfPtr conf,
> +                                     char ***retshargv,
> +                                     size_t *retshargvlen)
>  {
>      size_t i;
> +    size_t len;
>      char **shargv = NULL;
> -    virConfValuePtr p;
> +    virConfValuePtr p, pp;
>  
>      p = virConfGetValue(conf, "shell");
> -    if (!p)
> -        return virStringSplit("/bin/sh -l", " ", 3);
> -
> -    if (p->type == VIR_CONF_LIST) {
> -        size_t len;
> -        virConfValuePtr pp;
> -
> +    if (!p) {
> +        len = 2; /* /bin/sh -l */
> +    } else if (p->type == VIR_CONF_LIST) {
>          /* Calc length and check items */
>          for (len = 0, pp = p->list; pp; len++, pp = pp->next) {
>              if (pp->type != VIR_CONF_STRING) {
> @@ -122,18 +121,41 @@ static char **virLoginShellGetShellArgv(virConfPtr conf)
>                  goto error;
>              }
>          }
> +    } else {
> +        virReportSystemError(EINVAL, "%s",
> +                             _("shell must be a list of strings"));
> +        goto error;
> +    }
>  
> -        if (VIR_ALLOC_N(shargv, len + 1) < 0)
> +    len++; /* NULL terminator */
> +
> +    if (VIR_ALLOC_N(shargv, len) < 0)
> +        goto error;
> +
> +    i = 0;
> +    if (!p) {
> +        if (VIR_STRDUP(shargv[i++], "/bin/sh") < 0)
>              goto error;
> -        for (i = 0, pp = p->list; pp; i++, pp = pp->next) {
> -            if (VIR_STRDUP(shargv[i], pp->str) < 0)
> +        if (VIR_STRDUP(shargv[i++], "-l") < 0)
> +            goto error;
> +    } else if (p->type == VIR_CONF_LIST) {
> +        for (pp = p->list; pp; pp = pp->next) {
> +            if (VIR_STRDUP(shargv[i++], pp->str) < 0)
>                  goto error;
>          }
>      }
> -    return shargv;
> +
> +    shargv[i] = NULL;
> +
> +    *retshargvlen = i;
> +    *retshargv = shargv;
> +
> +    return 0;
>   error:
> +    *retshargv = NULL;
> +    *retshargvlen = 0;
>      virStringFreeList(shargv);
> -    return NULL;
> +    return -1;
>  }
>  
>  static char *progname;

Right in here somewhere there's some 'usage()' that should probably be
updated.

> @@ -177,6 +199,7 @@ main(int argc, char **argv)
>      gid_t gid = getgid();
>      char *name = NULL;
>      char **shargv = NULL;
> +    size_t shargvlen = 0;
>      virSecurityModelPtr secmodel = NULL;
>      virSecurityLabelPtr seclabel = NULL;
>      virDomainPtr dom = NULL;
> @@ -190,6 +213,7 @@ main(int argc, char **argv)
>      int *fdlist = NULL;
>      int openmax;
>      size_t i;
> +    const char *cmdstr = NULL;
>  
>      struct option opt[] = {
>          {"help", no_argument, NULL, 'h'},

Should this add a "-c" w/ required_argument?

I also see the "V" lists "optional_argument", but that's not part of the
"hV" below, so shouldn't it be no_argument?

ACK with the changes -

John

> @@ -220,7 +244,7 @@ main(int argc, char **argv)
>          return ret;
>      }
>  
> -    while ((arg = getopt_long(argc, argv, "hV", opt, &longindex)) != -1) {
> +    while ((arg = getopt_long(argc, argv, "hVc:", opt, &longindex)) != -1) {
>          switch (arg) {
>          case 'h':
>              usage();
> @@ -230,6 +254,10 @@ main(int argc, char **argv)
>              show_version();
>              exit(EXIT_SUCCESS);
>  
> +        case 'c':
> +            cmdstr = optarg;
> +            break;
> +
>          case '?':
>          default:
>              usage();
> @@ -265,7 +293,7 @@ main(int argc, char **argv)
>      if (virLoginShellAllowedUser(conf, name, groups) < 0)
>          goto cleanup;
>  
> -    if (!(shargv = virLoginShellGetShellArgv(conf)))
> +    if (virLoginShellGetShellArgv(conf, &shargv, &shargvlen) < 0)
>          goto cleanup;
>  
>      conn = virConnectOpen("lxc:///");
> @@ -318,6 +346,16 @@ main(int argc, char **argv)
>          goto cleanup;
>      }
>  
> +    if (cmdstr) {
> +        if (VIR_REALLOC_N(shargv, shargvlen + 3) < 0)
> +            goto cleanup;
> +        if (VIR_STRDUP(shargv[shargvlen++], "-c") < 0)
> +            goto cleanup;
> +        if (VIR_STRDUP(shargv[shargvlen++], cmdstr) < 0)
> +            goto cleanup;
> +        shargv[shargvlen] = NULL;
> +    }
> +
>      /* A fork is required to create new process in correct pid namespace.  */
>      if ((cpid = virFork()) < 0)
>          goto cleanup;
> 




More information about the libvir-list mailing list