[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:23:30 UTC 2014


On Thu, 2014-10-09 at 15:54 +0900, TAMUKI Shoichi wrote:
> 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.

This is obviously a festering problem and one that has already been
addressed in the Fedora and CentOS templates in a different manner and
additional patches have been submitted and under discussion.  Did you
even bother to read the code in the Fedora and CentOS templates?

Please immediately table this patch until further discussion can be
completed and a consensus achieved.

> Signed-off-by: TAMUKI Shoichi <tamuki at linet.gr.jp>
> ---
> 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
> +

-- 
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/19feff58/attachment.sig>


More information about the lxc-devel mailing list