[lxc-devel] [PATCH v2 3/3] Improve setting the default password in a new container

Michael H. Warfield mhw at WittsEnd.com
Fri Oct 10 03:32:29 UTC 2014


On Thu, 2014-10-09 at 18:46 +0000, Serge Hallyn wrote:
> Quoting TAMUKI Shoichi (tamuki at linet.gr.jp):
> > The default password in a new container is now auto-generated using
> > phoneme rules and (good) random numbers.
> > 
> > Even if the default random password is set in a distribution-specific
> > template and you use the download template to pull a pre-built rootfs
> > image, you will get the same password every time unless the pre-built
> > rootfs image is updated.
> > 
> > So, the default random password in a new container is to be set after
> > container creation.  The user names whose passwords to be changed are
> > stored in *.chpasswd file which is located at /usr/share/lxc/config.
> > Each line of the file specifies a user name whose password is to be
> > changed.  If the target *.chpasswd file does not exist, no password is
> > changed in a new container.
> > 
> > Signed-off-by: TAMUKI Shoichi <tamuki at linet.gr.jp>
> 
> Hi.
> 
> After a "brief" look over this patch I didn't see any technical problems,
> but let's take a step back and talk about the usage of this.
> 
> Three things I'd like to discuss, and I'm curious whether you've talked
> at all with Michael or Stéphane about this approach.
> 
> 1. You print out the new passwords on lxc-create command line.
>    a. You always do this, -q or no (trivial fix)
>    b. The resulting passwords aren't available for later perusal.  This
>       works fine if i sit at the command line and create one container,
>       but not if a script is creating one
>       One might say "well you can reset it using attach" but if that is
>       our feeling then we may as well set all passwords to invalid and
>       always require users to set them.

> 2. The resetting of passwords is guided only via the template.chpasswd
>    files.  There should be a way to override these via the configuration file
>    or command line.  What about simply making this a list in the configuration
>    file?  So the $distro.common configuration file could have

The Fedora and CentOS templates also have the options for setting up
password templates using a variety of mechanisms including random
password characters and environment settings.  These settings can be
overrident by environment variables on a invocation basis avoiding
exposure on command lines and contain variables that control printing
generated passwords and storing generated passwords and controlling if
passwords should be "expired".

> lxc.chpasswd = joe
> lxc.chpasswd = root

>    then my own configuration file could include that and do

> lxc.chpasswd =

>    to clear out the list and request no changes

> 3. To fix 1b, I think it'd be ok to have a (default-off) config item

> lxc.store-passwords = 1

>    which will store the uname:passwd entries in 700-mode
>    $lcxpath/$container/passwords

> Comments?

What's wrong with the method which is currently being used in the CentOS
and Fedora templates?  We've needed this for ages in the other
templates, and we've got at least two buzilla security reports on them,
but it's already a done deal in these two.  Now we're reinventing the
wheel again?  My last patch to implement common features for this was
submitted a couple of months ago but put on hold for revisions.  This
patch is in direct conflict.  We're going to have to have a consensus,
much like we had to have when the autoboot system was discussed. 

> > ---
> > v2:
> >   - adjust to fit with the other patches.
> > 
> >  config/templates/Makefile.am           |  27 +++-
> >  config/templates/altlinux.chpasswd     |   1 +
> >  config/templates/archlinux.chpasswd    |   1 +
> >  config/templates/busybox.chpasswd      |   1 +
> >  config/templates/centos.chpasswd       |   1 +
> >  config/templates/debian.chpasswd       |   1 +
> >  config/templates/fedora.chpasswd       |   1 +
> >  config/templates/gentoo.chpasswd       |   1 +
> >  config/templates/openmandriva.chpasswd |   1 +
> >  config/templates/opensuse.chpasswd     |   1 +
> >  config/templates/oracle.chpasswd       |   2 +
> >  config/templates/plamo.chpasswd        |   1 +
> >  config/templates/ubuntu.chpasswd       |   1 +
> >  src/lxc/Makefile.am                    |   2 +
> >  src/lxc/lxccontainer.c                 | 220 ++++++++++++++++++++++++++++++++-
> >  src/lxc/pwgen.c                        | 201 ++++++++++++++++++++++++++++++
> >  src/lxc/pwgen.h                        |  26 ++++
> >  17 files changed, 485 insertions(+), 4 deletions(-)
> >  create mode 100644 config/templates/altlinux.chpasswd
> >  create mode 100644 config/templates/archlinux.chpasswd
> >  create mode 100644 config/templates/busybox.chpasswd
> >  create mode 100644 config/templates/centos.chpasswd
> >  create mode 100644 config/templates/debian.chpasswd
> >  create mode 100644 config/templates/fedora.chpasswd
> >  create mode 100644 config/templates/gentoo.chpasswd
> >  create mode 100644 config/templates/openmandriva.chpasswd
> >  create mode 100644 config/templates/opensuse.chpasswd
> >  create mode 100644 config/templates/oracle.chpasswd
> >  create mode 100644 config/templates/plamo.chpasswd
> >  create mode 100644 config/templates/ubuntu.chpasswd
> >  create mode 100644 src/lxc/pwgen.c
> >  create mode 100644 src/lxc/pwgen.h
> > 
> > diff --git a/config/templates/Makefile.am b/config/templates/Makefile.am
> > index 82ca8be..22b231f 100644
> > --- a/config/templates/Makefile.am
> > +++ b/config/templates/Makefile.am
> > @@ -1,30 +1,55 @@
> >  templatesconfigdir=@LXCTEMPLATECONFIG@
> >  
> > -EXTRA_DIST = common.seccomp
> > +EXTRA_DIST = \
> > +	altlinux.chpasswd \
> > +	archlinux.chpasswd \
> > +	busybox.chpasswd \
> > +	centos.chpasswd \
> > +	common.seccomp \
> > +	debian.chpasswd \
> > +	fedora.chpasswd \
> > +	gentoo.chpasswd \
> > +	openmandriva.chpasswd \
> > +	opensuse.chpasswd \
> > +	oracle.chpasswd \
> > +	plamo.chpasswd \
> > +	ubuntu.chpasswd
> >  
> >  templatesconfig_DATA = \
> > +	altlinux.chpasswd \
> > +	archlinux.chpasswd \
> >  	archlinux.common.conf \
> >  	archlinux.userns.conf \
> > +	busybox.chpasswd \
> > +	centos.chpasswd \
> >  	centos.common.conf \
> >  	centos.userns.conf \
> >  	common.conf \
> >  	common.seccomp \
> > +	debian.chpasswd \
> >  	debian.common.conf \
> >  	debian.userns.conf \
> > +	fedora.chpasswd \
> >  	fedora.common.conf \
> >  	fedora.userns.conf \
> > +	gentoo.chpasswd \
> >  	gentoo.common.conf \
> >  	gentoo.moresecure.conf \
> >  	gentoo.userns.conf \
> > +	openmandriva.chpasswd \
> > +	opensuse.chpasswd \
> >  	opensuse.common.conf \
> >  	opensuse.userns.conf \
> > +	oracle.chpasswd \
> >  	oracle.common.conf \
> >  	oracle.userns.conf \
> > +	plamo.chpasswd \
> >  	plamo.common.conf \
> >  	plamo.userns.conf \
> >  	ubuntu-cloud.common.conf \
> >  	ubuntu-cloud.lucid.conf \
> >  	ubuntu-cloud.userns.conf \
> > +	ubuntu.chpasswd
> >  	ubuntu.common.conf \
> >  	ubuntu.lucid.conf \
> >  	ubuntu.userns.conf \
> > diff --git a/config/templates/altlinux.chpasswd b/config/templates/altlinux.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/altlinux.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/archlinux.chpasswd b/config/templates/archlinux.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/archlinux.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/busybox.chpasswd b/config/templates/busybox.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/busybox.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/centos.chpasswd b/config/templates/centos.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/centos.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/debian.chpasswd b/config/templates/debian.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/debian.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/fedora.chpasswd b/config/templates/fedora.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/fedora.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/gentoo.chpasswd b/config/templates/gentoo.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/gentoo.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/openmandriva.chpasswd b/config/templates/openmandriva.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/openmandriva.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/opensuse.chpasswd b/config/templates/opensuse.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/opensuse.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/oracle.chpasswd b/config/templates/oracle.chpasswd
> > new file mode 100644
> > index 0000000..e4b3edb
> > --- /dev/null
> > +++ b/config/templates/oracle.chpasswd
> > @@ -0,0 +1,2 @@
> > +root
> > +oracle
> > diff --git a/config/templates/plamo.chpasswd b/config/templates/plamo.chpasswd
> > new file mode 100644
> > index 0000000..d8649da
> > --- /dev/null
> > +++ b/config/templates/plamo.chpasswd
> > @@ -0,0 +1 @@
> > +root
> > diff --git a/config/templates/ubuntu.chpasswd b/config/templates/ubuntu.chpasswd
> > new file mode 100644
> > index 0000000..e9e5f7c
> > --- /dev/null
> > +++ b/config/templates/ubuntu.chpasswd
> > @@ -0,0 +1 @@
> > +ubuntu
> > diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
> > index da3f78e..fe6793f 100644
> > --- a/src/lxc/Makefile.am
> > +++ b/src/lxc/Makefile.am
> > @@ -89,6 +89,7 @@ liblxc_so_SOURCES = \
> >  	lxcutmp.c lxcutmp.h \
> >  	lxclock.h lxclock.c \
> >  	lxccontainer.c lxccontainer.h \
> > +	pwgen.c pwgen.h \
> >  	version.h \
> >  	\
> >  	$(LSM_SOURCES)
> > @@ -117,6 +118,7 @@ AM_CFLAGS=-I$(top_srcdir)/src \
> >  	-DLXCINITDIR=\"$(LXCINITDIR)\" \
> >  	-DLIBEXECDIR=\"$(LIBEXECDIR)\" \
> >  	-DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\" \
> > +	-DLXCTEMPLATECONFIG=\"$(LXCTEMPLATECONFIG)\" \
> >  	-DLOGPATH=\"$(LOGPATH)\" \
> >  	-DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" \
> >  	-DLXC_USERNIC_DB=\"$(LXC_USERNIC_DB)\" \
> > diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> > index 4df1a4b..e3d08c6 100644
> > --- a/src/lxc/lxccontainer.c
> > +++ b/src/lxc/lxccontainer.c
> > @@ -56,6 +56,7 @@
> >  #include "namespace.h"
> >  #include "lxclock.h"
> >  #include "sync.h"
> > +#include "pwgen.h"
> >  
> >  #if HAVE_IFADDRS_H
> >  #include <ifaddrs.h>
> > @@ -868,6 +869,50 @@ static char *get_template_path(const char *t)
> >  	return tpath;
> >  }
> >  
> > +/*
> > + * Given the '-t' template option to lxc-create, figure out what to
> > + * do.  If the template is a full executable path, just return NULL.
> > + * If the template is 'download', use the effective template instead.
> > + * If it is something like 'ubuntu', then return LXCTEMPLATECONFIG/
> > + * ubuntu.chpasswd.  Return the chpasswd file, or return NULL if not
> > + * exist.
> > + */
> > +static char *get_chpasswd_path(const char *t, char *const argv[])
> > +{
> > +	int i, ret, len;
> > +	const char *et = t;
> > +	char *p, *chpwpath;
> > +
> > +	if (t[0] == '/')
> > +		return NULL;
> > +	if (!strcmp(t, "download")) {
> > +		for (i = 0, et = NULL; argv[i] && !et; i++)
> > +			if (!strcmp(argv[i], "-d"))
> > +				et = argv[i + 1];
> > +			else if (!strncmp(argv[i], "--d", 3))
> > +				et = ((p = strchr(argv[i], '=')) != NULL)
> > +						? p + 1 : argv[i + 1];
> > +	} else
> > +		et = t;
> > +
> > +	len = strlen(LXCTEMPLATECONFIG) + strlen(et) + strlen(".chpasswd") + 2;
> > +	chpwpath = malloc(len);
> > +	if (!chpwpath)
> > +		return NULL;
> > +	ret = snprintf(chpwpath, len, "%s/%s.chpasswd", LXCTEMPLATECONFIG, et);
> > +	if (ret < 0 || ret >= len) {
> > +		free(chpwpath);
> > +		return NULL;
> > +	}
> > +	if (access(chpwpath, R_OK) < 0) {
> > +		NOTICE("nothing to do chpasswd: %s", et);
> > +		free(chpwpath);
> > +		return NULL;
> > +	}
> > +
> > +	return chpwpath;
> > +}
> > +
> >  static char *lxcbasename(char *path)
> >  {
> >  	char *p = path + strlen(path) - 1;
> > @@ -881,8 +926,9 @@ static char *figureout_rootfs(struct lxc_conf *conf);
> >  static char **prepend_lxc_usernsexec(char **tpath, struct lxc_conf *conf,
> >  		int nargs, char **newargv);
> >  
> > -static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet,
> > -				char *const argv[])
> > +static bool create_run_template(struct lxc_container *c, char *tpath,
> > +		char **const uname, char **const passwd, bool quiet,
> > +		char *const argv[])
> >  {
> >  	pid_t pid;
> >  
> > @@ -982,6 +1028,101 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
> >  		return false;
> >  	}
> >  
> > +	if (!uname)
> > +		return true;
> > +
> > +	pid = fork();
> > +	if (pid < 0) {
> > +		SYSERROR("failed to fork task for chpasswd");
> > +		return false;
> > +	}
> > +
> > +	if (pid == 0) { // child
> > +		char *sharg, *rootfs;
> > +		char *chpasswd = NULL;
> > +		int i, j;
> > +		int ret, len, nargs = 0;
> > +		char *p;
> > +		char **newargv;
> > +		struct lxc_conf *conf = c->lxc_conf;
> > +
> > +		if (quiet) {
> > +			close(0);
> > +			close(1);
> > +			close(2);
> > +			open("/dev/zero", O_RDONLY);
> > +			open("/dev/null", O_RDWR);
> > +			open("/dev/null", O_RDWR);
> > +		}
> > +
> > +		rootfs=figureout_rootfs(conf);
> > +		if (!rootfs)
> > +			exit(1);
> > +
> > +		/*
> > +		 * create our new array, pre-pend the template name and
> > +		 * base args
> > +		 */
> > +		nargs += 3; // "sh", "-c" and
> > +		// "echo \"$chpasswd\" | chroot $rootfs /usr/sbin/chpasswd"
> > +		// args
> > +
> > +		newargv = malloc(nargs * sizeof(*newargv));
> > +		if (!newargv)
> > +			exit(1);
> > +		newargv[0] = "sh";
> > +		newargv[1] = "-c";
> > +
> > +		for (i = j = 0; uname[i]; i++, j += len - 1) {
> > +			len = strlen(uname[i]) + strlen(passwd[i]) + 3;
> > +			chpasswd = realloc(chpasswd, j + len);
> > +			if (!chpasswd)
> > +				exit(1);
> > +			ret = snprintf(chpasswd + j, len, "%s:%s\n",
> > +					uname[i], passwd[i]);
> > +			if (ret < 0 || ret >= len)
> > +				exit(1);
> > +		}
> > +		if ((p = strrchr(chpasswd, '\n')) != NULL)
> > +			*p = '\0';
> > +
> > +		len = strlen("echo") + strlen(chpasswd)
> > +				+ strlen("chroot") + strlen(rootfs)
> > +				+ strlen("/usr/sbin/chpasswd") + 9;
> > +		sharg = malloc(len);
> > +		if (!sharg)
> > +			exit(1);
> > +		ret = snprintf(sharg, len,
> > +				"echo \"%s\" | chroot %s /usr/sbin/chpasswd",
> > +				chpasswd, rootfs);
> > +		if (ret < 0 || ret >= len)
> > +			exit(1);
> > +		newargv[2] = sharg;
> > +
> > +		/* add trailing NULL */
> > +		nargs++;
> > +		newargv = realloc(newargv, nargs * sizeof(*newargv));
> > +		if (!newargv)
> > +			exit(1);
> > +		newargv[nargs - 1] = NULL;
> > +
> > +		tpath = "sh";
> > +		/* prepend the template command with lxc-usernsexec */
> > +		if (!lxc_list_empty(&conf->id_map))
> > +			newargv = prepend_lxc_usernsexec(&tpath, conf,
> > +					nargs, newargv);
> > +
> > +		/* execute */
> > +		execvp(tpath, newargv);
> > +		SYSERROR("failed to execute chpasswd");
> > +		exit(1);
> > +	}
> > +
> > +	if (wait_for_pid(pid) != 0) {
> > +		ERROR("chpasswd for %s failed", c->name);
> > +		return false;
> > +	}
> > +
> >  	return true;
> >  }
> >  
> > @@ -1281,6 +1422,12 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
> >  	bool ret = false;
> >  	pid_t pid;
> >  	char *tpath = NULL;
> > +	char *chpwpath = NULL;
> > +	char **uname = NULL, **passwd = NULL;
> > +	int i;
> > +	FILE *fp;
> > +	char *p, *line = NULL;
> > +	size_t len = 0;
> >  	int partial_fd;
> >  
> >  	if (!c)
> > @@ -1292,6 +1439,49 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
> >  			ERROR("bad template: %s", t);
> >  			goto out;
> >  		}
> > +		chpwpath = get_chpasswd_path(t, argv);
> > +		if (chpwpath) {
> > +			fp = fopen(chpwpath, "r");
> > +			for (i = 0; getline(&line, &len, fp) != -1; i++) {
> > +				if ((p = strchr(line, '\n')) != NULL)
> > +					*p = '\0';
> > +				if (!(uname = realloc(uname,
> > +						(i + 1) * sizeof(*uname)))) {
> > +					SYSERROR("out of memory");
> > +					exit(1);
> > +				}
> > +				if (!(uname[i] = malloc(strlen(line) + 1))) {
> > +					SYSERROR("out of memory");
> > +					exit(1);
> > +				}
> > +				strcpy(uname[i], line);
> > +				if (!(passwd = realloc(passwd,
> > +						(i + 1) * sizeof(*passwd)))) {
> > +					SYSERROR("out of memory");
> > +					exit(1);
> > +				}
> > +				if (!(passwd[i] = malloc(11))) {
> > +					SYSERROR("out of memory");
> > +					exit(1);
> > +				}
> > +				pw_phonemes(passwd[i], 10);
> > +			}
> > +			if (line)
> > +				free(line);
> > +			fclose(fp);
> > +			if (!(uname = realloc(uname,
> > +					(i + 1) * sizeof(*uname)))) {
> > +				SYSERROR("out of memory");
> > +				exit(1);
> > +			}
> > +			uname[i] = NULL;
> > +			if (!(passwd = realloc(passwd,
> > +					(i + 1) * sizeof(*passwd)))) {
> > +				SYSERROR("out of memory");
> > +				exit(1);
> > +			}
> > +			passwd[i] = NULL;
> > +		}
> >  	}
> >  
> >  	/*
> > @@ -1381,9 +1571,17 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
> >  	if (!load_config_locked(c, c->configfile))
> >  		goto out_unlock;
> >  
> > -	if (!create_run_template(c, tpath, !!(flags & LXC_CREATE_QUIET), argv))
> > +	if (!create_run_template(c, tpath, uname, passwd,
> > +			!!(flags & LXC_CREATE_QUIET), argv))
> >  		goto out_unlock;
> >  
> > +	if (uname)
> > +		for (i = 0; uname[i]; i++)
> > +			printf("The default %s password is: %s\n",
> > +					uname[i], passwd[i]);
> > +	else
> > +		printf("No password is changed.\n");
> > +
> >  	// now clear out the lxc_conf we have, reload from the created
> >  	// container
> >  	lxcapi_clear_config(c);
> > @@ -1405,6 +1603,22 @@ out:
> >  free_tpath:
> >  	if (tpath)
> >  		free(tpath);
> > +	if (chpwpath)
> > +		free(chpwpath);
> > +	if (uname) {
> > +		char **pp;
> > +
> > +		for (pp = uname; *pp; pp++)
> > +			free(*pp);
> > +		free(uname);
> > +	}
> > +	if (passwd) {
> > +		char **pp;
> > +
> > +		for (pp = passwd; *pp; pp++)
> > +			free(*pp);
> > +		free(passwd);
> > +	}
> >  	return ret;
> >  }
> >  
> > diff --git a/src/lxc/pwgen.c b/src/lxc/pwgen.c
> > new file mode 100644
> > index 0000000..c5a83d0
> > --- /dev/null
> > +++ b/src/lxc/pwgen.c
> > @@ -0,0 +1,201 @@
> > +/*
> > + * pwgen.c --- generate secure password using phoneme rules and
> > + *             (good) random numbers.
> > + *
> > + * Copyright (C) 2001,2002 by Theodore Ts'o
> > + * Copyright (C) 2014 by TAMUKI Shoichi
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2.1 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> > + */
> > +
> > +#include <string.h>
> > +#include <ctype.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <stdlib.h>
> > +#include <sys/time.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +#include "pwgen.h"
> > +
> > +struct pw_element {
> > +	const char *str;
> > +	int flags;
> > +};
> > +
> > +/* Flags for the pw_element */
> > +#define CONSONANT	0x0001
> > +#define VOWEL		0x0002
> > +#define DIPTHONG	0x0004
> > +#define NOT_FIRST	0x0008
> > +
> > +struct pw_element elements[] = {
> > +	{ "a",	VOWEL },
> > +	{ "ae", VOWEL | DIPTHONG },
> > +	{ "ah",	VOWEL | DIPTHONG },
> > +	{ "ai", VOWEL | DIPTHONG },
> > +	{ "b",  CONSONANT },
> > +	{ "c",	CONSONANT },
> > +	{ "ch", CONSONANT | DIPTHONG },
> > +	{ "d",	CONSONANT },
> > +	{ "e",	VOWEL },
> > +	{ "ee", VOWEL | DIPTHONG },
> > +	{ "ei",	VOWEL | DIPTHONG },
> > +	{ "f",	CONSONANT },
> > +	{ "g",	CONSONANT },
> > +	{ "gh", CONSONANT | DIPTHONG | NOT_FIRST },
> > +	{ "h",	CONSONANT },
> > +	{ "i",	VOWEL },
> > +	{ "ie", VOWEL | DIPTHONG },
> > +	{ "j",	CONSONANT },
> > +	{ "k",	CONSONANT },
> > +	{ "l",	CONSONANT },
> > +	{ "m",	CONSONANT },
> > +	{ "n",	CONSONANT },
> > +	{ "ng",	CONSONANT | DIPTHONG | NOT_FIRST },
> > +	{ "o",	VOWEL },
> > +	{ "oh",	VOWEL | DIPTHONG },
> > +	{ "oo",	VOWEL | DIPTHONG },
> > +	{ "p",	CONSONANT },
> > +	{ "ph",	CONSONANT | DIPTHONG },
> > +	{ "qu",	CONSONANT | DIPTHONG },
> > +	{ "r",	CONSONANT },
> > +	{ "s",	CONSONANT },
> > +	{ "sh",	CONSONANT | DIPTHONG },
> > +	{ "t",	CONSONANT },
> > +	{ "th",	CONSONANT | DIPTHONG },
> > +	{ "u",	VOWEL },
> > +	{ "v",	CONSONANT },
> > +	{ "w",	CONSONANT },
> > +	{ "x",	CONSONANT },
> > +	{ "y",	CONSONANT },
> > +	{ "z",	CONSONANT }
> > +};
> > +
> > +#define NUM_ELEMENTS (sizeof(elements) / sizeof(struct pw_element))
> > +
> > +/* Flags for the pwgen function */
> > +#define PW_DIGITS	0x0001	/* At least one digit */
> > +#define PW_UPPERS	0x0002	/* At least one upper letter */
> > +
> > +static int pw_number(int max_num);
> > +static int get_random_fd(void);
> > +
> > +void pw_phonemes(char *buf, int size)
> > +{
> > +	int feature_flags, should_be, prev, first;
> > +	int c, i, len, flags;
> > +	const char *str;
> > +
> > +try_again:
> > +	feature_flags = PW_DIGITS | PW_UPPERS;
> > +	should_be = (pw_number(2)) ? VOWEL : CONSONANT;
> > +	prev = 0, first = 1;
> > +	c = 0;
> > +	while (c < size) {
> > +		str = elements[i = pw_number(NUM_ELEMENTS)].str;
> > +		len = strlen(str);
> > +		flags = elements[i].flags;
> > +		/* Don't allow us to overflow the buffer */
> > +		if (c + len > size)
> > +			continue;
> > +		/* Filter on the basic type of the next element */
> > +		if (!(flags & should_be))
> > +			continue;
> > +		/* Handle the NOT_FIRST flag */
> > +		if (first && flags & NOT_FIRST)
> > +			continue;
> > +		/* Don't allow VOWEL followed a Vowel/Dipthong pair */
> > +		if (prev & VOWEL && flags & VOWEL && flags & DIPTHONG)
> > +			continue;
> > +		/*
> > +		 * OK, we found an element which matches our criteria,
> > +		 * let's do it!
> > +		 */
> > +		strcpy(buf + c, str);
> > +		if ((first || flags & CONSONANT) && !pw_number(5)) {
> > +			buf[c] = toupper(buf[c]);
> > +			feature_flags &= ~PW_UPPERS;
> > +		}
> > +		/* Time to stop? */
> > +		if ((c += len) == size)
> > +			break;
> > +		if (!first && pw_number(10) < 3) {
> > +			buf[c++] = '0' + pw_number(10), buf[c] = 0;
> > +			feature_flags &= ~PW_DIGITS;
> > +			should_be = (pw_number(2)) ? VOWEL : CONSONANT;
> > +			prev = 0, first = 1;
> > +			continue;
> > +		}
> > +		/* OK, figure out what the next element should be */
> > +		should_be = (should_be == CONSONANT) ? VOWEL
> > +				: ((prev & VOWEL || flags & DIPTHONG
> > +				|| pw_number(5) < 2) ? VOWEL : CONSONANT);
> > +		prev = flags, first = 0;
> > +	}
> > +	if (feature_flags & (PW_DIGITS | PW_UPPERS))
> > +		goto try_again;
> > +}
> > +
> > +/*
> > + * Generate a random number n, where 0 <= n < max_num, using
> > + * /dev/urandom if possible.
> > + */
> > +static int pw_number(int max_num)
> > +{
> > +	int fd, i;
> > +	unsigned int rand_num;
> > +	char *cp = (char *) &rand_num;
> > +	int nbytes = 4, lose_counter = 0;
> > +
> > +	if ((fd = get_random_fd()) >= 0)
> > +		while (nbytes > 0)
> > +			if ((i = read(fd, cp, nbytes)) < 0
> > +					&& (errno == EINTR || errno == EAGAIN))
> > +				continue;
> > +			else if (i <= 0) {
> > +				if (lose_counter++ == 8)
> > +					break;
> > +			} else
> > +				cp += i, nbytes -= i, lose_counter = 0;
> > +	close(fd);
> > +	if (nbytes == 0)
> > +		return rand_num % max_num;
> > +	/* OK, we weren't able to use /dev/random, fall back to rand/rand48 */
> > +	return (int) (drand48() * max_num);
> > +}
> > +
> > +/* Borrowed/adapted from e2fsprogs's UUID generation code */
> > +static int get_random_fd(void)
> > +{
> > +	static int fd = -2;
> > +	struct timeval tv;
> > +	int i;
> > +
> > +	if (fd == -2) {
> > +		gettimeofday(&tv, 0);
> > +		if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
> > +			fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
> > +		srand48(tv.tv_sec << 9 ^ tv.tv_usec >> 11 ^ getpid()
> > +				^ getpgrp() << 15);
> > +	}
> > +	/* Crank the random number generator a few times */
> > +	gettimeofday(&tv, 0);
> > +	for (i = 0; i < ((tv.tv_sec ^ tv.tv_usec) & 0x1f); i++)
> > +		drand48();
> > +	return fd;
> > +}
> > +
> > diff --git a/src/lxc/pwgen.h b/src/lxc/pwgen.h
> > new file mode 100644
> > index 0000000..9d0adc5
> > --- /dev/null
> > +++ b/src/lxc/pwgen.h
> > @@ -0,0 +1,26 @@
> > +/*
> > + * pwgen.h --- header file for password generator
> > + *
> > + * Copyright (C) 2001,2002 by Theodore Ts'o
> > + * Copyright (C) 2014 by TAMUKI Shoichi
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2.1 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> > + */
> > +
> > +#ifndef __PWGEN_H
> > +#define __PWGEN_H
> > +extern void pw_phonemes(char *buf, int size);
> > +#endif
> > +
> > -- 
> > 1.9.0
> > _______________________________________________
> > lxc-devel mailing list
> > lxc-devel at lists.linuxcontainers.org
> > http://lists.linuxcontainers.org/listinfo/lxc-devel

-- 
Michael H. Warfield (AI4NB) | (770) 978-7061 |  mhw at WittsEnd.com
   /\/\|=mhw=|\/\/          | (678) 463-0932 |  http://www.wittsend.com/mhw/
   NIC whois: MHW9          | An optimist believes we live in the best of all
 PGP Key: 0x674627FF        | possible worlds.  A pessimist is sure of it!

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 465 bytes
Desc: This is a digitally signed message part
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20141009/075b75eb/attachment-0001.sig>


More information about the lxc-devel mailing list