render / rpms / libvirt

Forked from rpms/libvirt 8 months ago
Clone
43fe83
From 838cf2f32c9f7050da3ae5a31b3108ce77684839 Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <838cf2f32c9f7050da3ae5a31b3108ce77684839.1377873638.git.jdenemar@redhat.com>
43fe83
From: Dan Walsh <dwalsh@redhat.com>
43fe83
Date: Tue, 13 Aug 2013 15:20:40 +0100
43fe83
Subject: [PATCH] Introduce a virt-login-shell binary
43fe83
43fe83
For https://bugzilla.redhat.com/show_bug.cgi?id=988491
43fe83
43fe83
Add a virt-login-shell binary that can be set as a user's
43fe83
shell, such that when they login, it causes them to enter
43fe83
the LXC container with a name matching their user name.
43fe83
43fe83
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
43fe83
(cherry picked from commit 54d69f540c9928da98f10202b3f21b7abb00bac1)
43fe83
---
43fe83
 .gitignore                  |   1 +
43fe83
 libvirt.spec.in             |   3 +
43fe83
 po/POTFILES.in              |   1 +
43fe83
 tools/Makefile.am           |  30 +++-
43fe83
 tools/virt-login-shell.c    | 350 ++++++++++++++++++++++++++++++++++++++++++++
43fe83
 tools/virt-login-shell.conf |  26 ++++
43fe83
 tools/virt-login-shell.pod  |  62 ++++++++
43fe83
 7 files changed, 472 insertions(+), 1 deletion(-)
43fe83
 create mode 100644 tools/virt-login-shell.c
43fe83
 create mode 100644 tools/virt-login-shell.conf
43fe83
 create mode 100644 tools/virt-login-shell.pod
43fe83
43fe83
diff --git a/po/POTFILES.in b/po/POTFILES.in
43fe83
index 1fd84af..884b70a 100644
43fe83
--- a/po/POTFILES.in
43fe83
+++ b/po/POTFILES.in
43fe83
@@ -231,3 +231,4 @@ tools/virt-host-validate-common.c
43fe83
 tools/virt-host-validate-lxc.c
43fe83
 tools/virt-host-validate-qemu.c
43fe83
 tools/virt-host-validate.c
43fe83
+tools/virt-login-shell.c
43fe83
diff --git a/tools/Makefile.am b/tools/Makefile.am
43fe83
index 644a86d..00c582a 100644
43fe83
--- a/tools/Makefile.am
43fe83
+++ b/tools/Makefile.am
43fe83
@@ -37,6 +37,7 @@ EXTRA_DIST = \
43fe83
 	virt-pki-validate.in				\
43fe83
 	virt-sanlock-cleanup.in				\
43fe83
 	virt-sanlock-cleanup.8				\
43fe83
+	virt-login-shell.pod				\
43fe83
 	virsh.pod					\
43fe83
 	libvirt-guests.sysconf				\
43fe83
 	virsh-edit.c					\
43fe83
@@ -52,8 +53,11 @@ EXTRA_DIST = \
43fe83
 
43fe83
 DISTCLEANFILES =
43fe83
 
43fe83
+confdir = $(sysconfdir)/libvirt
43fe83
+conf_DATA = virt-login-shell.conf
43fe83
+
43fe83
 bin_SCRIPTS = virt-xml-validate virt-pki-validate
43fe83
-bin_PROGRAMS = virsh virt-host-validate
43fe83
+bin_PROGRAMS = virsh virt-host-validate virt-login-shell
43fe83
 libexec_SCRIPTS = libvirt-guests.sh
43fe83
 
43fe83
 if WITH_SANLOCK
43fe83
@@ -65,6 +69,7 @@ dist_man1_MANS = \
43fe83
 		virt-host-validate.1 \
43fe83
 		virt-pki-validate.1 \
43fe83
 		virt-xml-validate.1 \
43fe83
+		virt-login-shell.1 \
43fe83
 		virsh.1
43fe83
 if WITH_SANLOCK
43fe83
 dist_man8_MANS = virt-sanlock-cleanup.8
43fe83
@@ -128,6 +133,24 @@ virt_host_validate_CFLAGS = \
43fe83
 		$(COVERAGE_CFLAGS)				\
43fe83
 		$(NULL)
43fe83
 
43fe83
+virt_login_shell_SOURCES =					\
43fe83
+		virt-login-shell.conf				\
43fe83
+		virt-login-shell.c
43fe83
+
43fe83
+virt_login_shell_LDFLAGS = $(COVERAGE_LDFLAGS)
43fe83
+virt_login_shell_LDADD =					\
43fe83
+		$(STATIC_BINARIES)				\
43fe83
+		$(PIE_LDFLAGS)					\
43fe83
+		$(RELRO_LDFLAGS) \
43fe83
+		../src/libvirt.la				\
43fe83
+		../src/libvirt-lxc.la				\
43fe83
+		../gnulib/lib/libgnu.la
43fe83
+
43fe83
+virt_login_shell_CFLAGS =					\
43fe83
+		$(WARN_CFLAGS)					\
43fe83
+		$(PIE_CFLAGS)					\
43fe83
+		$(COVERAGE_CFLAGS)
43fe83
+
43fe83
 virsh_SOURCES =							\
43fe83
 		console.c console.h				\
43fe83
 		virsh.c virsh.h					\
43fe83
@@ -189,6 +212,11 @@ virsh_win_icon.$(OBJEXT): virsh_win_icon.rc
43fe83
 	  --output-format coff --output $@
43fe83
 endif
43fe83
 
43fe83
+virt-login-shell.1: virt-login-shell.pod $(top_srcdir)/configure.ac
43fe83
+	$(AM_V_GEN)$(POD2MAN) $< $(srcdir)/$@ \
43fe83
+	    && if grep 'POD ERROR' $(srcdir)/$@ ; then \
43fe83
+		rm $(srcdir)/$@; exit 1; fi
43fe83
+
43fe83
 virsh.1: virsh.pod $(top_srcdir)/configure.ac
43fe83
 	$(AM_V_GEN)$(POD2MAN) $< $(srcdir)/$@ \
43fe83
 	    && if grep 'POD ERROR' $(srcdir)/$@ ; then \
43fe83
diff --git a/tools/virt-login-shell.c b/tools/virt-login-shell.c
43fe83
new file mode 100644
43fe83
index 0000000..ffbc713
43fe83
--- /dev/null
43fe83
+++ b/tools/virt-login-shell.c
43fe83
@@ -0,0 +1,350 @@
43fe83
+/*
43fe83
+ * virt-login-shell.c: a shell to connect to a container
43fe83
+ *
43fe83
+ * Copyright (C) 2013 Red Hat, Inc.
43fe83
+ *
43fe83
+ * This library is free software; you can redistribute it and/or
43fe83
+ * modify it under the terms of the GNU Lesser General Public
43fe83
+ * License as published by the Free Software Foundation; either
43fe83
+ * version 2.1 of the License, or (at your option) any later version.
43fe83
+ *
43fe83
+ * This library is distributed in the hope that it will be useful,
43fe83
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
43fe83
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43fe83
+ * Lesser General Public License for more details.
43fe83
+ *
43fe83
+ * You should have received a copy of the GNU Lesser General Public
43fe83
+ * License along with this library.  If not, see
43fe83
+ * <http://www.gnu.org/licenses/>.
43fe83
+ *
43fe83
+ * Daniel Walsh <dwalsh@redhat.com>
43fe83
+ */
43fe83
+#include <config.h>
43fe83
+
43fe83
+#include <stdarg.h>
43fe83
+#include <getopt.h>
43fe83
+#include <stdio.h>
43fe83
+#include <errno.h>
43fe83
+#include <stdlib.h>
43fe83
+#include <fnmatch.h>
43fe83
+
43fe83
+#include "internal.h"
43fe83
+#include "virerror.h"
43fe83
+#include "virconf.h"
43fe83
+#include "virutil.h"
43fe83
+#include "virfile.h"
43fe83
+#include "virprocess.h"
43fe83
+#include "configmake.h"
43fe83
+#include "virstring.h"
43fe83
+#include "viralloc.h"
43fe83
+#include "vircommand.h"
43fe83
+#define VIR_FROM_THIS VIR_FROM_NONE
43fe83
+
43fe83
+static ssize_t nfdlist = 0;
43fe83
+static int *fdlist = NULL;
43fe83
+static const char *conf_file = SYSCONFDIR "/libvirt/virt-login-shell.conf";
43fe83
+
43fe83
+static void virLoginShellFini(virConnectPtr conn, virDomainPtr  dom)
43fe83
+{
43fe83
+    size_t i;
43fe83
+
43fe83
+    for (i = 0; i < nfdlist; i++)
43fe83
+        VIR_FORCE_CLOSE(fdlist[i]);
43fe83
+    VIR_FREE(fdlist);
43fe83
+    nfdlist = 0;
43fe83
+    if (dom)
43fe83
+        virDomainFree(dom);
43fe83
+    if (conn)
43fe83
+        virConnectClose(conn);
43fe83
+}
43fe83
+
43fe83
+static int virLoginShellAllowedUser(virConfPtr conf,
43fe83
+                                    const char *name,
43fe83
+                                    gid_t *groups)
43fe83
+{
43fe83
+    virConfValuePtr p;
43fe83
+    int ret = -1;
43fe83
+    char *ptr = NULL;
43fe83
+    size_t i;
43fe83
+    char *gname = NULL;
43fe83
+
43fe83
+    p = virConfGetValue(conf, "allowed_users");
43fe83
+    if (p && p->type == VIR_CONF_LIST) {
43fe83
+        virConfValuePtr pp;
43fe83
+
43fe83
+        /* Calc length and check items */
43fe83
+        for (pp = p->list; pp; pp = pp->next) {
43fe83
+            if (pp->type != VIR_CONF_STRING) {
43fe83
+                virReportSystemError(EINVAL, "%s", _("shell must be a list of strings"));
43fe83
+                goto cleanup;
43fe83
+            } else {
43fe83
+                /*
43fe83
+                  If string begins with a % this indicates a linux group.
43fe83
+                  Check to see if the user is in the Linux Group.
43fe83
+                */
43fe83
+                if (pp->str[0] == '%') {
43fe83
+                    ptr = &pp->str[1];
43fe83
+                    if (!ptr)
43fe83
+                        continue;
43fe83
+                    for (i = 0; groups[i]; i++) {
43fe83
+                        if (!(gname = virGetGroupName(groups[i])))
43fe83
+                            continue;
43fe83
+                        if (fnmatch(ptr, gname, 0) == 0) {
43fe83
+                            ret = 0;
43fe83
+                            goto cleanup;
43fe83
+                        }
43fe83
+                        VIR_FREE(gname);
43fe83
+                    }
43fe83
+                    VIR_FREE(groups);
43fe83
+                    continue;
43fe83
+                }
43fe83
+                if (fnmatch(pp->str, name, 0) == 0) {
43fe83
+                    ret = 0;
43fe83
+                    goto cleanup;
43fe83
+                }
43fe83
+            }
43fe83
+        }
43fe83
+    }
43fe83
+    virReportSystemError(EPERM, _("%s not listed as an allowed_users in %s"), name, conf_file);
43fe83
+cleanup:
43fe83
+    VIR_FREE(gname);
43fe83
+    VIR_FREE(groups);
43fe83
+    return ret;
43fe83
+}
43fe83
+
43fe83
+static char **virLoginShellGetShellArgv(virConfPtr conf)
43fe83
+{
43fe83
+    size_t i;
43fe83
+    char **shargv=NULL;
43fe83
+    virConfValuePtr p;
43fe83
+
43fe83
+    p = virConfGetValue(conf, "shell");
43fe83
+    if (!p)
43fe83
+        return virStringSplit("/bin/sh -l", " ", 3);
43fe83
+
43fe83
+    if (p && p->type == VIR_CONF_LIST) {
43fe83
+        size_t len;
43fe83
+        virConfValuePtr pp;
43fe83
+
43fe83
+        /* Calc length and check items */
43fe83
+        for (len = 0, pp = p->list; pp; len++, pp = pp->next) {
43fe83
+            if (pp->type != VIR_CONF_STRING) {
43fe83
+                virReportSystemError(EINVAL, "%s", _("shell must be a list of strings"));
43fe83
+                goto error;
43fe83
+            }
43fe83
+        }
43fe83
+
43fe83
+        if (VIR_ALLOC_N(shargv, len + 1) < 0)
43fe83
+            goto error;
43fe83
+        for (i = 0, pp = p->list; pp; i++, pp = pp->next) {
43fe83
+            if (VIR_STRDUP(shargv[i], pp->str) < 0)
43fe83
+                goto error;
43fe83
+        }
43fe83
+        shargv[len] = NULL;
43fe83
+    }
43fe83
+    return shargv;
43fe83
+error:
43fe83
+    virStringFreeList(shargv);
43fe83
+    return NULL;
43fe83
+}
43fe83
+
43fe83
+static char *progname;
43fe83
+
43fe83
+/*
43fe83
+ * Print usage
43fe83
+ */
43fe83
+static void
43fe83
+usage(void)
43fe83
+{
43fe83
+    fprintf(stdout, _("\n"
43fe83
+                      "%s is a privileged program that allows non root users \n"
43fe83
+                      "specified in %s to join a Linux container \n"
43fe83
+                      "with a matching user name and launch a shell. \n"
43fe83
+                      "\n%s [options]\n\n"
43fe83
+                      "  options:\n"
43fe83
+                      "    -h | --help             this help:\n\n"), progname, conf_file, progname);
43fe83
+    return;
43fe83
+}
43fe83
+
43fe83
+int
43fe83
+main(int argc, char **argv)
43fe83
+{
43fe83
+    virConfPtr conf = NULL;
43fe83
+    const char *login_shell_path = conf_file;
43fe83
+    pid_t cpid;
43fe83
+    int ret = EXIT_FAILURE;
43fe83
+    int status;
43fe83
+    int status2;
43fe83
+    uid_t uid = getuid();
43fe83
+    gid_t gid = getgid();
43fe83
+    char *name = NULL;
43fe83
+    char **shargv = NULL;
43fe83
+    virSecurityModelPtr secmodel = NULL;
43fe83
+    virSecurityLabelPtr seclabel = NULL;
43fe83
+    virDomainPtr dom = NULL;
43fe83
+    virConnectPtr conn = NULL;
43fe83
+    char *homedir = NULL;
43fe83
+    int arg;
43fe83
+    int longindex = -1;
43fe83
+    int ngroups;
43fe83
+    gid_t *groups = NULL;
43fe83
+
43fe83
+    struct option opt[] = {
43fe83
+        {"help", no_argument, NULL, 'h'},
43fe83
+        {NULL, 0, NULL, 0}
43fe83
+    };
43fe83
+    if (virInitialize() < 0) {
43fe83
+        fprintf(stderr, _("Failed to initialize libvirt Error Handling"));
43fe83
+        return EXIT_FAILURE;
43fe83
+    }
43fe83
+
43fe83
+    virSetErrorFunc(NULL, NULL);
43fe83
+    virSetErrorLogPriorityFunc(NULL);
43fe83
+
43fe83
+    progname = argv[0];
43fe83
+    if (!setlocale(LC_ALL, "")) {
43fe83
+        perror("setlocale");
43fe83
+        /* failure to setup locale is not fatal */
43fe83
+    }
43fe83
+    if (!bindtextdomain(PACKAGE, LOCALEDIR)) {
43fe83
+        perror("bindtextdomain");
43fe83
+        return ret;
43fe83
+    }
43fe83
+    if (!textdomain(PACKAGE)) {
43fe83
+        perror("textdomain");
43fe83
+        return ret;
43fe83
+    }
43fe83
+
43fe83
+    /* The only option we support is help
43fe83
+     */
43fe83
+    while ((arg = getopt_long(argc, argv, "h", opt, &longindex)) != -1) {
43fe83
+        switch (arg) {
43fe83
+        case 'h':
43fe83
+            usage();
43fe83
+            exit(EXIT_SUCCESS);
43fe83
+            break;
43fe83
+        }
43fe83
+    }
43fe83
+
43fe83
+    if (argc > optind) {
43fe83
+        virReportSystemError(EINVAL, _("%s takes no options"), progname);
43fe83
+        errno = EINVAL;
43fe83
+        goto cleanup;
43fe83
+    }
43fe83
+
43fe83
+    if (uid == 0) {
43fe83
+        virReportSystemError(EPERM, _("%s must be run by non root users"), progname);
43fe83
+        goto cleanup;
43fe83
+    }
43fe83
+
43fe83
+    name = virGetUserName(uid);
43fe83
+    if (!name)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    homedir = virGetUserDirectoryByUID(uid);
43fe83
+    if (!homedir)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    if (!(conf = virConfReadFile(login_shell_path, 0)))
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    if ((ngroups = virGetGroupList(uid, gid, &groups)) < 0)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    if (virLoginShellAllowedUser(conf, name, groups) < 0)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    if (!(shargv = virLoginShellGetShellArgv(conf)))
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    conn = virConnectOpen("lxc:///");
43fe83
+    if (!conn)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    dom = virDomainLookupByName(conn, name);
43fe83
+    if (!dom)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    if (!virDomainIsActive(dom) && virDomainCreate(dom)) {
43fe83
+        virErrorPtr last_error;
43fe83
+        last_error = virGetLastError();
43fe83
+        if (last_error->code != VIR_ERR_OPERATION_INVALID) {
43fe83
+            virReportSystemError(last_error->code,_("Can't create %s container: %s"), name, virGetLastErrorMessage());
43fe83
+            goto cleanup;
43fe83
+        }
43fe83
+    }
43fe83
+
43fe83
+    if ((nfdlist = virDomainLxcOpenNamespace(dom, &fdlist, 0)) < 0)
43fe83
+        goto cleanup;
43fe83
+    if (VIR_ALLOC(secmodel) < 0)
43fe83
+        goto cleanup;
43fe83
+    if (VIR_ALLOC(seclabel) < 0)
43fe83
+        goto cleanup;
43fe83
+    if (virNodeGetSecurityModel(conn, secmodel) < 0)
43fe83
+        goto cleanup;
43fe83
+    if (virDomainGetSecurityLabel(dom, seclabel) < 0)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    if (virFork(&cpid) < 0)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    if (cpid == 0) {
43fe83
+        pid_t ccpid;
43fe83
+
43fe83
+        /* Fork once because we don't want to affect
43fe83
+         * virt-login-shell's namespace itself
43fe83
+         */
43fe83
+        if (virSetUIDGID(0, 0, NULL, 0) < 0)
43fe83
+            return EXIT_FAILURE;
43fe83
+
43fe83
+        if (virDomainLxcEnterSecurityLabel(secmodel,
43fe83
+                                           seclabel,
43fe83
+                                           NULL,
43fe83
+                                           0) < 0)
43fe83
+            return EXIT_FAILURE;
43fe83
+
43fe83
+        if (nfdlist > 0) {
43fe83
+            if (virDomainLxcEnterNamespace(dom,
43fe83
+                                           nfdlist,
43fe83
+                                           fdlist,
43fe83
+                                           NULL,
43fe83
+                                           NULL,
43fe83
+                                           0) < 0)
43fe83
+                return EXIT_FAILURE;
43fe83
+        }
43fe83
+
43fe83
+        ret = virSetUIDGID(uid, gid, groups, ngroups);
43fe83
+        VIR_FREE(groups);
43fe83
+        if (ret < 0)
43fe83
+            return EXIT_FAILURE;
43fe83
+
43fe83
+        if (virFork(&ccpid) < 0)
43fe83
+            return EXIT_FAILURE;
43fe83
+
43fe83
+        if (ccpid == 0) {
43fe83
+            if (chdir(homedir) < 0) {
43fe83
+                virReportSystemError(errno, _("Unable chdir(%s)"), homedir);
43fe83
+                return EXIT_FAILURE;
43fe83
+            }
43fe83
+            if (execv(shargv[0], (char *const*) shargv) < 0) {
43fe83
+                virReportSystemError(errno, _("Unable exec shell %s"), shargv[0]);
43fe83
+                return -errno;
43fe83
+            }
43fe83
+        }
43fe83
+        return virProcessWait(ccpid, &status2);
43fe83
+    }
43fe83
+    ret = virProcessWait(cpid, &status);
43fe83
+
43fe83
+cleanup:
43fe83
+    virConfFree(conf);
43fe83
+    virLoginShellFini(conn, dom);
43fe83
+    virStringFreeList(shargv);
43fe83
+    VIR_FREE(name);
43fe83
+    VIR_FREE(homedir);
43fe83
+    VIR_FREE(seclabel);
43fe83
+    VIR_FREE(secmodel);
43fe83
+    VIR_FREE(groups);
43fe83
+    if (ret)
43fe83
+        virDispatchError(NULL);
43fe83
+    return ret;
43fe83
+}
43fe83
diff --git a/tools/virt-login-shell.conf b/tools/virt-login-shell.conf
43fe83
new file mode 100644
43fe83
index 0000000..835fd3f
43fe83
--- /dev/null
43fe83
+++ b/tools/virt-login-shell.conf
43fe83
@@ -0,0 +1,26 @@
43fe83
+# Master configuration file for the virt-login-shell program.
43fe83
+# All settings described here are optional - if omitted, sensible
43fe83
+# defaults are used.
43fe83
+
43fe83
+# By default, virt-login-shell will connect you to a container running
43fe83
+# with the /bin/sh program.  Modify the shell variable if you want your
43fe83
+# users to run a different shell or a setup container when joining a
43fe83
+# container.  Shell commands must be a list of commands/options separated by
43fe83
+# comma and delimited by square brackets. Defaults to: /bin/sh -l.
43fe83
+# Modify and uncomment the following to modify the login shell.
43fe83
+# shell = [ "/bin/sh",  "-l" ]
43fe83
+
43fe83
+# allowed_users specifies the user names of all users that are allowed to
43fe83
+# execute virt-login-shell.  You can specify the users as a comma
43fe83
+# separated list of usernames or user groups.
43fe83
+# The list of names support glob syntax.
43fe83
+# To disallow all users (default)
43fe83
+# allowed_users = []
43fe83
+# If you do not specify any names (default) then no one is allowed
43fe83
+# to use this executable.
43fe83
+# To allow fred and joe only
43fe83
+# allowed_users = ["fred", "joe"]
43fe83
+# To allow all users within a specific group prefix the group name with %.
43fe83
+# allowed_users = ["%engineers"]
43fe83
+# To allow all users specify the following
43fe83
+# allowed_users = [ "*" ]
43fe83
diff --git a/tools/virt-login-shell.pod b/tools/virt-login-shell.pod
43fe83
new file mode 100644
43fe83
index 0000000..0cd35cf
43fe83
--- /dev/null
43fe83
+++ b/tools/virt-login-shell.pod
43fe83
@@ -0,0 +1,62 @@
43fe83
+=head1 NAME
43fe83
+
43fe83
+virt-login-shell - tool to execute a shell within a container matching the users name
43fe83
+
43fe83
+=head1 SYNOPSIS
43fe83
+
43fe83
+B<virt-login-shell>
43fe83
+
43fe83
+=head1 DESCRIPTION
43fe83
+
43fe83
+The B<virt-login-shell> program is setuid shell that is used to join
43fe83
+an LXC container that matches the users name.  If the container is not
43fe83
+running virt-login-shell will attempt to start the container.
43fe83
+virt-sandbox-shell is not allowed to be run by root.  Normal users will get
43fe83
+added to a container that matches their username, if it exists.  And they are
43fe83
+configured in /etc/libvirt/virt-login-shell.conf.
43fe83
+
43fe83
+The basic structure of most virt-login-shell usage is:
43fe83
+
43fe83
+  virt-login-shell
43fe83
+
43fe83
+=head1 CONFIG
43fe83
+
43fe83
+By default, virt-login-shell will execute the /bin/sh program for the user.
43fe83
+You can modify this behaviour by defining the shell variable in /etc/libvirt/virt-login-shell.conf.
43fe83
+
43fe83
+eg.  shell = [ "/bin/ksh", "--login"]
43fe83
+
43fe83
+By default no users are allowed to user virt-login-shell, if you want to allow
43fe83
+certain users to use virt-login-shell, you need to modify the allowed_users variable in /etc/libvirt/virt-login-shell.conf.
43fe83
+
43fe83
+eg. allowed_users = [ "tom", "dick", "harry" ]
43fe83
+
43fe83
+=head1 BUGS
43fe83
+
43fe83
+Report any bugs discovered to the libvirt community via the mailing
43fe83
+list C<http://libvirt.org/contact.html> or bug tracker C<http://libvirt.org/bugs.html>.
43fe83
+Alternatively report bugs to your software distributor / vendor.
43fe83
+
43fe83
+=head1 AUTHORS
43fe83
+
43fe83
+  Please refer to the AUTHORS file distributed with libvirt.
43fe83
+
43fe83
+  Daniel Walsh <dwalsh at redhat dot com>
43fe83
+
43fe83
+=head1 COPYRIGHT
43fe83
+
43fe83
+Copyright (C) 2013 Red Hat, Inc., and the authors listed in the
43fe83
+libvirt AUTHORS file.
43fe83
+
43fe83
+=head1 LICENSE
43fe83
+
43fe83
+virt-login-shell is distributed under the terms of the GNU LGPL v2+.
43fe83
+This is free software; see the source for copying conditions. There
43fe83
+is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
43fe83
+PURPOSE
43fe83
+
43fe83
+=head1 SEE ALSO
43fe83
+
43fe83
+L<virsh(1)>, L<http://www.libvirt.org/>
43fe83
+
43fe83
+=cut
43fe83
-- 
43fe83
1.8.3.2
43fe83