[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