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

Stéphane Graber stgraber at ubuntu.com
Thu Oct 9 19:21:55 UTC 2014


On Thu, Oct 09, 2014 at 06:46:19PM +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
> 
> 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?

Please don't use the lxc.* namespace for that as those keys are
restricted to the internal config parser.

But having something like template.users.* or similar would indeed be fine.

> 
> > ---
> > 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

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20141009/8d2ea5f5/attachment-0001.sig>


More information about the lxc-devel mailing list