[libvirt] [PATCH 2/2] virt-login-shell joins users into lxc container.

Daniel P. Berrange berrange at redhat.com
Wed Jul 31 18:57:04 UTC 2013


On Tue, Jul 30, 2013 at 03:55:45PM -0400, dwalsh at redhat.com wrote:
> From: Dan Walsh <dwalsh at redhat.com>
> 
> Openshift wants to have their gears stuck into a container when they login
> to the system.  virt-login-shell will join a running gear with the username of
> the person running it, or attempt to start the container if it is not running.
> (Currently containers do not exist if they are not running, so I can not test
> this feature. But the code is there).
> 
> This tool needs to be setuid since joining a container (nsjoin) requires privs.
> The root user is not allowed to execute this command. When this tool is
> run by a normal user it will only join the "users" container.
> 
> Only users who are listed as valid_users in /etc/libvirt/virt-login-shell.conf
> are allowed to join containers using this tool. By default no users are allowed.
> ---
> +static ssize_t nfdlist = 0;
> +static int *fdlist = NULL;
> +static const char *conf_file = SYSCONFDIR "/libvirt/virt-login-shell.conf";
> +
> +static void virLoginShellFini(virConnectPtr conn, virDomainPtr  dom)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < nfdlist; i++)
> +	VIR_FORCE_CLOSE(fdlist[i]);
> +    VIR_FREE(fdlist);
> +    nfdlist = 0;
> +    if (dom)
> +	virDomainFree(dom);
> +    if (conn)
> +	virConnectClose(conn);

There are lots of tabs used for indent here and later in this
file. Please check with 'make syntax-check'.

> +static int virLoginShellAllowedUser(virConfPtr conf,
> +				    uid_t uid,
> +				    gid_t gid,
> +				    const char *name)
> +{
> +    virConfValuePtr p;
> +    int ret = -1;
> +    char *ptr = NULL;
> +    size_t i;
> +    gid_t *groups = NULL;
> +    char *gname = NULL;
> +
> +    p = virConfGetValue(conf, "allowed_users");
> +    if (p && p->type == VIR_CONF_LIST) {
> +	virConfValuePtr pp;
> +
> +	/* Calc length and check items */
> +	for (pp = p->list; pp; pp = pp->next) {
> +	    if (pp->type != VIR_CONF_STRING) {
> +		virReportSystemError(EINVAL, "%s", _("shell must be a list of strings\n"));
> +		goto cleanup;
> +	    } else {
> +		/*
> +		   If string begins with a % this indicates a linux group.
> +		   Check to see if the user is in the Linux Group.
> +		*/
> +		if (pp->str[0] == '%') {
> +		    ptr = &pp->str[1];
> +		    if (!ptr)
> +			continue;
> +		    if (virGetGroupList(uid, gid, &groups) < 0) {
> +			goto cleanup;
> +		    }
> +		    for (i = 0; groups[i]; i++) {
> +			if (!(gname = virGetGroupName(groups[i])))
> +			    continue;
> +			if (fnmatch(ptr, gname, 0) == 0) {
> +			    ret = 0;
> +			    goto cleanup;
> +			}
> +			VIR_FREE(gname);
> +		    }
> +		    VIR_FREE(groups);
> +		    continue;
> +		}
> +		if (fnmatch(pp->str, name, 0) == 0) {
> +		    ret = 0;
> +		    goto cleanup;
> +		}
> +	    }
> +	}
> +    }
> +    virReportSystemError(EPERM, _("%s not listed as an allowed_users in %s"), name, conf_file);
> +    errno = EPERM;

No need to set errno if you using virReportSystemError().

> +cleanup:
> +    VIR_FREE(gname);
> +    VIR_FREE(groups);
> +    return ret;
> +}
> +

> +int
> +main(int argc, char **argv)
> +{

> +
> +    struct option opt[] = {
> +	{"help", no_argument, NULL, 'h'},
> +	{NULL, 0, NULL, 0}
> +    };
> +    virReportSystemError(1, "%s %d %s", "Test1", argc, argv[0]);

Accidental debug line left in I presume

> +    if (virInitialize() < 0) {
> +	fprintf(stderr, _("Failed to initialize libvirt Error Handling"));
> +	return EXIT_FAILURE;
> +    }
> +    virReportSystemError(EINVAL, "%s", "Test2");

And here

> +
> +    if (virErrorInitialize() < 0) {
> +	fprintf(stderr, _("Failed to initialize libvirt Error Handling"));
> +	return EXIT_FAILURE;
> +    }

Actually no need to call virErrorInitialize() - virInitialize
takes care of that for you

> +    if (uid == 0) {
> +	virReportSystemError(EPERM, _("%s must be run by non root users"), progname);
> +
> +	errno = EPERM;

No need to set errno.


> +    if (virFork(&cpid) < 0)
> +	goto cleanup;
> +
> +    if (cpid == 0) {
> +	gid_t *groups = NULL;
> +	int ngroups;
> +	pid_t ccpid;
> +
> +	/* Fork once because we don't want to affect
> +	 * virt-login-shell's namespace itself
> +	 */
> +	if (virSetUIDGID(0, 0, NULL, 0) < 0)
> +	    return EXIT_FAILURE;
> +
> +	if (virDomainLxcEnterSecurityLabel(secmodel,
> +					   seclabel,
> +					   NULL,
> +					   0) < 0)
> +	    return EXIT_FAILURE;
> +
> +	if (nfdlist > 0) {
> +	    if (virDomainLxcEnterNamespace(dom,
> +					   nfdlist,
> +					   fdlist,
> +					   NULL,
> +					   NULL,
> +					   0) < 0)
> +		return EXIT_FAILURE;
> +	}
> +
> +	if ((ngroups = virGetGroupList(uid, gid, &groups)) < 0)
> +	    return EXIT_FAILURE;

virGetGroupList isn't safe to call after fork(). Need to
move it earlier in this function.

> +
> +	ret = virSetUIDGID(uid, gid, groups, ngroups);
> +	VIR_FREE(groups);
> +	if (ret < 0)
> +	    return EXIT_FAILURE;
> +
> +	if (virFork(&ccpid) < 0)
> +	    return EXIT_FAILURE;
> +
> +	if (ccpid == 0) {
> +	    if (chdir(homedir) < 0) {
> +		virReportSystemError(errno, _("Unable chdir(%s)"), homedir);
> +		return EXIT_FAILURE;
> +	    }
> +	    if (execv(shargv[0], (char *const*) shargv) < 0) {
> +		virReportSystemError(errno, _("Unable exec shell %s"), shargv[0]);
> +		return -errno;
> +	    }
> +	}
> +	return virProcessWait(ccpid, &status2);
> +    }
> +    ret = virProcessWait(cpid, &status);
> +

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list