[Pkg-shadow-devel] [shadow] 01/05: Add debian/patches/userns: patches to enable use of subuids (Closes: #739981)

Micah Anderson micah at moszumanska.debian.org
Wed Feb 26 16:42:56 UTC 2014


This is an automated email from the git hooks/post-receive script.

micah pushed a commit to branch master
in repository shadow.

commit 13f031cd67eafa1e497cfc438ba8a3f9747a699c
Author: Micah Anderson <micah at riseup.net>
Date:   Tue Feb 25 22:38:58 2014 -0500

    Add debian/patches/userns: patches to enable use of subuids (Closes: #739981)
---
 debian/changelog                                   |    5 +
 debian/patches/1000_configure_userns               |  105 ++
 debian/patches/series                              |   17 +
 debian/patches/userns/01_userns_doc                |  334 +++++++
 debian/patches/userns/02_userns_doc_login.defs     |  218 +++++
 .../userns/03_userns_implement_commonio_append     |  110 +++
 .../patches/userns/04_userns_add_backend_support   |  685 +++++++++++++
 .../userns/05_userns_implemend_find_new_sub_xids   |  283 ++++++
 debian/patches/userns/06_userns_userdel            |  236 +++++
 debian/patches/userns/07_userns_useradd            |  285 ++++++
 debian/patches/userns/08_userns_detect_busy_subids |  133 +++
 debian/patches/userns/09_userns_usermod            |  536 +++++++++++
 debian/patches/userns/10_userns_newusers           |  256 +++++
 debian/patches/userns/11_userns_newxidmap          | 1004 ++++++++++++++++++++
 debian/patches/userns/12_userns_selinuxlibs        |   13 +
 .../patches/userns/13_subordinate_parse_static_buf |   23 +
 debian/patches/userns/14_fix_getopt                |   24 +
 .../userns/16_add-argument-sanity-checking.patch   |   80 ++
 debian/patches/userns/manpagetypo                  |   26 +
 19 files changed, 4373 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 872ed86..79cdfc3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,5 +1,6 @@
 shadow (1:4.2-1) UNRELEASED; urgency=low
 
+  [ Nicolas FRANCOIS (Nekral) ]
   * New upstream release. Fixes:
     - Invalid free() in su fixed by using strdup(). Thanks to Serge
       Hallyn for the patch. Closes: #691459
@@ -31,6 +32,10 @@ shadow (1:4.2-1) UNRELEASED; urgency=low
   * debian/login.su.pam: Enable pam_limits by default. Closes: #705301
   * debian/rules: Set default editor to sensible-editor for vipw.
     Closes: #688252
+  [ Micah Anderson ]
+  * added debian/patches/userns to enable use of subuids, plus some bugfix 
+    patches on top of them, patches from Eric Biederman, pulled from
+    Ubuntu. Closes: #739981
 
  -- Christian Perrier <bubulle at debian.org>  Sat, 27 Jul 2013 20:07:18 +0200
 
diff --git a/debian/patches/1000_configure_userns b/debian/patches/1000_configure_userns
new file mode 100644
index 0000000..a198cf9
--- /dev/null
+++ b/debian/patches/1000_configure_userns
@@ -0,0 +1,105 @@
+=== modified file 'etc/login.defs'
+Index: shadow/etc/login.defs
+===================================================================
+--- shadow.orig/etc/login.defs	2014-02-16 19:31:38.934898148 -0500
++++ shadow/etc/login.defs	2014-02-16 19:31:38.926898149 -0500
+@@ -229,7 +229,7 @@
+ # Extra per user uids
+ SUB_UID_MIN		   100000
+ SUB_UID_MAX		600100000
+-SUB_UID_COUNT		    10000
++SUB_UID_COUNT		    65536
+ 
+ #
+ # Min/max values for automatic gid selection in groupadd
+@@ -242,7 +242,7 @@
+ # Extra per user group ids
+ SUB_GID_MIN		   100000
+ SUB_GID_MAX		600100000
+-SUB_GID_COUNT		    10000
++SUB_GID_COUNT		    65536
+ 
+ #
+ # Max number of login retries if password is bad
+Index: shadow/src/newusers.c
+===================================================================
+--- shadow.orig/src/newusers.c	2014-02-16 19:31:38.934898148 -0500
++++ shadow/src/newusers.c	2014-02-16 19:31:38.926898149 -0500
+@@ -946,8 +946,8 @@
+ #ifdef SHADOWGRP
+ 	is_shadow_grp = sgr_file_present ();
+ #endif
+-	is_sub_uid = sub_uid_file_present ();
+-	is_sub_gid = sub_gid_file_present ();
++	is_sub_uid = sub_uid_file_present () && !rflg;
++	is_sub_gid = sub_gid_file_present () && !rflg;
+ 
+ 	open_files ();
+ 
+Index: shadow/src/useradd.c
+===================================================================
+--- shadow.orig/src/useradd.c	2014-02-16 19:31:38.934898148 -0500
++++ shadow/src/useradd.c	2014-02-16 19:31:38.926898149 -0500
+@@ -1978,6 +1978,10 @@
+ #endif				/* USE_PAM */
+ #endif				/* ACCT_TOOLS_SETUID */
+ 
++	/* Needed for userns check */
++	uid_t uid_min = (uid_t) getdef_ulong ("UID_MIN", 1000UL);
++	uid_t uid_max = (uid_t) getdef_ulong ("UID_MAX", 60000UL);
++
+ 	/*
+ 	 * Get my name so that I can use it to report errors.
+ 	 */
+@@ -2001,18 +2005,20 @@
+ 	 */
+ 	user_groups[0] = (char *) 0;
+ 
+-
+ 	is_shadow_pwd = spw_file_present ();
+ #ifdef SHADOWGRP
+ 	is_shadow_grp = sgr_file_present ();
+ #endif
+-	is_sub_uid = sub_uid_file_present ();
+-	is_sub_gid = sub_gid_file_present ();
+-
+-	get_defaults ();
+ 
+ 	process_flags (argc, argv);
+ 
++	is_sub_uid = sub_uid_file_present () && !rflg &&
++	    (!user_id || (user_id <= uid_max && user_id >= uid_min));
++	is_sub_gid = sub_gid_file_present () && !rflg &&
++	    (!user_id || (user_id <= uid_max && user_id >= uid_min));
++
++	get_defaults ();
++
+ #ifdef ACCT_TOOLS_SETUID
+ #ifdef USE_PAM
+ 	{
+Index: shadow/libmisc/find_new_sub_uids.c
+===================================================================
+--- shadow.orig/libmisc/find_new_sub_uids.c	2014-02-16 19:31:38.934898148 -0500
++++ shadow/libmisc/find_new_sub_uids.c	2014-02-16 19:31:38.926898149 -0500
+@@ -56,7 +56,7 @@
+ 
+ 	min = getdef_ulong ("SUB_UID_MIN", 100000UL);
+ 	max = getdef_ulong ("SUB_UID_MAX", 600100000UL);
+-	count = getdef_ulong ("SUB_UID_COUNT", 10000);
++	count = getdef_ulong ("SUB_UID_COUNT", 65536);
+ 
+ 	if (min >= max || count >= max || (min + count) >= max) {
+ 		(void) fprintf (stderr,
+Index: shadow/libmisc/find_new_sub_gids.c
+===================================================================
+--- shadow.orig/libmisc/find_new_sub_gids.c	2014-02-16 19:32:21.298896382 -0500
++++ shadow/libmisc/find_new_sub_gids.c	2014-02-16 19:32:34.462895834 -0500
+@@ -56,7 +56,7 @@
+ 
+ 	min = getdef_ulong ("SUB_GID_MIN", 100000UL);
+ 	max = getdef_ulong ("SUB_GID_MAX", 600100000UL);
+-	count = getdef_ulong ("SUB_GID_COUNT", 10000);
++	count = getdef_ulong ("SUB_GID_COUNT", 65536);
+ 
+ 	if (min >= max || count >= max || (min + count) >= max) {
+ 		(void) fprintf (stderr,
diff --git a/debian/patches/series b/debian/patches/series
index 0a59b9f..e3d5fee 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -16,3 +16,20 @@
 523_su_arguments_are_no_more_concatenated_by_default
 508_nologin_in_usr_sbin
 505_useradd_recommend_adduser
+userns/01_userns_doc
+userns/02_userns_doc_login.defs
+userns/03_userns_implement_commonio_append
+userns/04_userns_add_backend_support
+userns/05_userns_implemend_find_new_sub_xids
+userns/06_userns_userdel
+userns/07_userns_useradd
+userns/08_userns_detect_busy_subids
+userns/09_userns_usermod
+userns/10_userns_newusers
+userns/11_userns_newxidmap
+userns/12_userns_selinuxlibs
+userns/13_subordinate_parse_static_buf
+userns/14_fix_getopt
+userns/manpagetypo
+userns/16_add-argument-sanity-checking.patch
+1000_configure_userns
diff --git a/debian/patches/userns/01_userns_doc b/debian/patches/userns/01_userns_doc
new file mode 100644
index 0000000..f5f5241
--- /dev/null
+++ b/debian/patches/userns/01_userns_doc
@@ -0,0 +1,334 @@
+From ebiederm at xmission.com  Tue Jan 22 09:14:18 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id DAC33C80F4; Tue, 22 Jan 2013 09:14:18 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=0.1 required=8.0 tests=BAD_ENC_HEADER,BAYES_00
+	autolearn=no version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id 274ACC80D1
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:14:14 +0000 (UTC)
+Received: from out01.mta.xmission.com ([166.70.13.231])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZuB-0006Xm-N5; Tue, 22 Jan 2013 02:12:31 -0700
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out01.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZuA-0005NR-BQ; Tue, 22 Jan 2013 02:12:30 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZu7-0004Pj-Ec; Tue, 22 Jan 2013 02:12:30 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:12:23 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <877gn5shs8.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX18YouPWtKNAX3LovSW2+p/ONbuCHMFEQpM=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 01/11] Documentation for /etc/subuid and /etc/subgid
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2071                                                  
+Status: RO
+Content-Length: 9835
+Lines: 286
+
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ man/Makefile.am  |    4 ++
+ man/subgid.5.xml |  120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ man/subuid.5.xml |  120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 244 insertions(+), 0 deletions(-)
+ create mode 100644 man/subgid.5.xml
+ create mode 100644 man/subuid.5.xml
+
+Index: shadow/man/Makefile.am
+===================================================================
+--- shadow.orig/man/Makefile.am	2013-02-01 15:26:14.428082026 -0600
++++ shadow/man/Makefile.am	2013-02-01 15:27:37.000000000 -0600
+@@ -43,6 +43,8 @@
+ 	man5/shadow.5 \
+ 	man1/su.1 \
+ 	man5/suauth.5 \
++	man5/subgid.5 \
++	man5/subuid.5 \
+ 	man8/useradd.8 \
+ 	man8/userdel.8 \
+ 	man8/usermod.8 \
+@@ -94,6 +96,8 @@
+ 	sg.1.xml \
+ 	su.1.xml \
+ 	suauth.5.xml \
++	subgid.5.xml \
++	subuid.5.xml \
+ 	useradd.8.xml \
+ 	userdel.8.xml \
+ 	usermod.8.xml \
+Index: shadow/man/subgid.5.xml
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/man/subgid.5.xml	2013-02-01 15:26:14.424082026 -0600
+@@ -0,0 +1,120 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!--
++   Copyright (c) 2013 Eric W. Biederman
++   All rights reserved.
++  
++   Redistribution and use in source and binary forms, with or without
++   modification, are permitted provided that the following conditions
++   are met:
++   1. Redistributions of source code must retain the above copyright
++      notice, this list of conditions and the following disclaimer.
++   2. Redistributions in binary form must reproduce the above copyright
++      notice, this list of conditions and the following disclaimer in the
++      documentation and/or other materials provided with the distribution.
++   3. The name of the copyright holders or contributors may not be used to
++      endorse or promote products derived from this software without
++      specific prior written permission.
++  
++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++   HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.5//EN"
++  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
++<!-- SHADOW-CONFIG-HERE -->
++]>
++<refentry id='subgid.5'>
++  <refmeta>
++    <refentrytitle>subgid</refentrytitle>
++    <manvolnum>5</manvolnum>
++    <refmiscinfo class="sectdesc">File Formats and Conversions</refmiscinfo>
++    <refmiscinfo class="source">shadow-utils</refmiscinfo>
++    <refmiscinfo class="version">&SHADOW_UTILS_VERSION;</refmiscinfo>
++  </refmeta>
++  <refnamediv id='name'>
++    <refname>subgid</refname>
++    <refpurpose>the subordinate gid file</refpurpose>
++  </refnamediv>
++
++  <refsect1 id='description'>
++    <title>DESCRIPTION</title>
++    <para>
++      Each line in <filename>/etc/subgid</filename> contains
++      a user id and a range of suboridinate user ids that user
++      is allowed to use.
++
++      This is specified with three fields delimited by colons
++      (<quote>:</quote>).
++      These fields are:
++    </para>
++    <itemizedlist mark='bullet'>
++      <listitem>
++	<para>login name</para>
++      </listitem>
++      <listitem>
++	<para>numerical subordinate user ID</para>
++      </listitem>
++      <listitem>
++	<para>numerical subordinate user ID count</para>
++      </listitem>
++    </itemizedlist>
++
++    <para>
++      This file specifies the group IDs to be that each user may use
++      with the <command>newgidmap</command> command that ordinary users can use to
++      configure gid mapping in a user namespace.
++    </para>
++
++    <para>
++      Multiple ranges may be specified per user ID.
++    </para>
++
++  </refsect1>
++
++  <refsect1 id='files'>
++    <title>FILES</title>
++    <variablelist>
++      <varlistentry>
++	<term><filename>/etc/subgid</filename></term>
++	<listitem>
++	  <para>Per user subordinate group IDs.</para>
++	</listitem>
++      </varlistentry>
++      <varlistentry>
++	<term><filename>/etc/subgid-</filename></term>
++	<listitem>
++	  <para>Backup file for /etc/subgid.</para>
++	</listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1 id='see_also'>
++    <title>SEE ALSO</title>
++    <para>
++      <citerefentry>
++	<refentrytitle>subuid</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>logindefs</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>newuidmap</refentrytitle><manvolnum>1</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>newgidmap</refentrytitle><manvolnum>1</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>usermod</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++    </para>
++  </refsect1>
++</refentry>
+Index: shadow/man/subuid.5.xml
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/man/subuid.5.xml	2013-02-01 15:26:14.424082026 -0600
+@@ -0,0 +1,120 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!--
++   Copyright (c) 2013 Eric W. Biederman
++   All rights reserved.
++  
++   Redistribution and use in source and binary forms, with or without
++   modification, are permitted provided that the following conditions
++   are met:
++   1. Redistributions of source code must retain the above copyright
++      notice, this list of conditions and the following disclaimer.
++   2. Redistributions in binary form must reproduce the above copyright
++      notice, this list of conditions and the following disclaimer in the
++      documentation and/or other materials provided with the distribution.
++   3. The name of the copyright holders or contributors may not be used to
++      endorse or promote products derived from this software without
++      specific prior written permission.
++  
++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++   HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.5//EN"
++  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
++<!-- SHADOW-CONFIG-HERE -->
++]>
++<refentry id='subuid.5'>
++  <refmeta>
++    <refentrytitle>subuid</refentrytitle>
++    <manvolnum>5</manvolnum>
++    <refmiscinfo class="sectdesc">File Formats and Conversions</refmiscinfo>
++    <refmiscinfo class="source">shadow-utils</refmiscinfo>
++    <refmiscinfo class="version">&SHADOW_UTILS_VERSION;</refmiscinfo>
++  </refmeta>
++  <refnamediv id='name'>
++    <refname>subuid</refname>
++    <refpurpose>the subordinate uid file</refpurpose>
++  </refnamediv>
++
++  <refsect1 id='description'>
++    <title>DESCRIPTION</title>
++    <para>
++      Each line in <filename>/etc/subuid</filename> contains
++      a user id and a range of suboridinate user ids that user
++      is allowed to use.
++
++      This is specified with three fields delimited by colons
++      (<quote>:</quote>).
++      These fields are:
++    </para>
++    <itemizedlist mark='bullet'>
++      <listitem>
++	<para>login name</para>
++      </listitem>
++      <listitem>
++	<para>numerical subordinate user ID</para>
++      </listitem>
++      <listitem>
++	<para>numerical subordinate user ID count</para>
++      </listitem>
++    </itemizedlist>
++
++    <para>
++      This file specifies the user IDs to be that each user may use
++      with the <command>newuidmap</command> command that ordinary users can use to
++      configure uid mapping in a user namespace.
++    </para>
++
++    <para>
++      Multiple ranges may be specified per user ID.
++    </para>
++
++  </refsect1>
++
++  <refsect1 id='files'>
++    <title>FILES</title>
++    <variablelist>
++      <varlistentry>
++	<term><filename>/etc/subuid</filename></term>
++	<listitem>
++	  <para>Per user subordinate user IDs.</para>
++	</listitem>
++      </varlistentry>
++      <varlistentry>
++	<term><filename>/etc/subuid-</filename></term>
++	<listitem>
++	  <para>Backup file for /etc/subuid.</para>
++	</listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1 id='see_also'>
++    <title>SEE ALSO</title>
++    <para>
++      <citerefentry>
++	<refentrytitle>subgid</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>logindefs</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>newuidmap</refentrytitle><manvolnum>1</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>newgidmap</refentrytitle><manvolnum>1</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>usermod</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++    </para>
++  </refsect1>
++</refentry>
diff --git a/debian/patches/userns/02_userns_doc_login.defs b/debian/patches/userns/02_userns_doc_login.defs
new file mode 100644
index 0000000..5d85cce
--- /dev/null
+++ b/debian/patches/userns/02_userns_doc_login.defs
@@ -0,0 +1,218 @@
+From ebiederm at xmission.com  Tue Jan 22 09:14:55 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id 140DBC80F4; Tue, 22 Jan 2013 09:14:55 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=0.1 required=8.0 tests=BAD_ENC_HEADER,BAYES_00
+	autolearn=no version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id 5D815C80D1
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:14:50 +0000 (UTC)
+Received: from out03.mta.xmission.com ([166.70.13.233])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZum-0006il-0f; Tue, 22 Jan 2013 02:13:08 -0700
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out03.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZul-0004GF-Id; Tue, 22 Jan 2013 02:13:07 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZuf-0004T0-MS; Tue, 22 Jan 2013 02:13:07 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:12:58 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <871uddshr9.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX19iYyOCEx6dl2v1Ya/KIGpixG5+3MVA1bY=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 02/11] login.defs.5: Document the new variables in login.defs
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2072                                                  
+Status: RO
+Content-Length: 7615
+Lines: 170
+
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ man/Makefile.am                    |    2 +
+ man/login.defs.5.xml               |    8 ++++++
+ man/login.defs.d/SUB_GID_COUNT.xml |   46 ++++++++++++++++++++++++++++++++++++
+ man/login.defs.d/SUB_UID_COUNT.xml |   46 ++++++++++++++++++++++++++++++++++++
+ 4 files changed, 102 insertions(+), 0 deletions(-)
+ create mode 100644 man/login.defs.d/SUB_GID_COUNT.xml
+ create mode 100644 man/login.defs.d/SUB_UID_COUNT.xml
+
+Index: shadow/man/Makefile.am
+===================================================================
+--- shadow.orig/man/Makefile.am	2013-02-01 15:27:51.048080390 -0600
++++ shadow/man/Makefile.am	2013-02-01 15:27:51.040080390 -0600
+@@ -163,6 +163,8 @@
+ 	USERDEL_CMD.xml \
+ 	USERGROUPS_ENAB.xml \
+ 	USE_TCB.xml \
++	SUB_GID_COUNT.xml \
++	SUB_UID_COUNT.xml \
+ 	SYS_GID_MAX.xml \
+ 	SYS_UID_MAX.xml
+ 
+Index: shadow/man/login.defs.5.xml
+===================================================================
+--- shadow.orig/man/login.defs.5.xml	2013-02-01 15:27:51.048080390 -0600
++++ shadow/man/login.defs.5.xml	2013-02-01 15:27:51.044080390 -0600
+@@ -78,6 +78,8 @@
+ <!ENTITY SULOG_FILE            SYSTEM "login.defs.d/SULOG_FILE.xml">
+ <!ENTITY SU_NAME               SYSTEM "login.defs.d/SU_NAME.xml">
+ <!ENTITY SU_WHEEL_ONLY         SYSTEM "login.defs.d/SU_WHEEL_ONLY.xml">
++<!ENTITY SUB_GID_COUNT         SYSTEM "login.defs.d/SUB_GID_COUNT.xml">
++<!ENTITY SUB_UID_COUNT         SYSTEM "login.defs.d/SUB_UID_COUNT.xml">
+ <!ENTITY SYS_GID_MAX           SYSTEM "login.defs.d/SYS_GID_MAX.xml">
+ <!ENTITY SYSLOG_SG_ENAB        SYSTEM "login.defs.d/SYSLOG_SG_ENAB.xml">
+ <!ENTITY SYSLOG_SU_ENAB        SYSTEM "login.defs.d/SYSLOG_SU_ENAB.xml">
+@@ -216,6 +218,8 @@
+       &SULOG_FILE;
+       &SU_NAME;
+       &SU_WHEEL_ONLY;
++      &SUB_GID_COUNT; <!-- documents also SUB_GID_MIN SUB_GID_MAX -->
++      &SUB_UID_COUNT; <!-- documents also SUB_UID_MIN SUB_UID_MAX -->
+       &SYS_GID_MAX; <!-- documents also SYS_GID_MIN -->
+       &SYS_UID_MAX; <!-- documents also SYS_UID_MIN -->
+       &SYSLOG_SG_ENAB;
+@@ -393,6 +397,8 @@
+ 	    PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE
+ 	    <phrase condition="sha_crypt">SHA_CRYPT_MAX_ROUNDS
+ 	    SHA_CRYPT_MIN_ROUNDS</phrase>
++	    SUB_GID_COUNT SUB_GID_MAX SUB_GID_MIN
++	    SUB_UID_COUNT SUB_UID_MAX SUB_UID_MIN
+ 	    SYS_GID_MAX SYS_GID_MIN SYS_UID_MAX SYS_UID_MIN UID_MAX UID_MIN
+ 	    UMASK
+ 	  </para>
+@@ -470,6 +476,8 @@
+ 	    GID_MAX GID_MIN
+ 	    MAIL_DIR MAX_MEMBERS_PER_GROUP
+ 	    PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE
++	    SUB_GID_COUNT SUB_GID_MAX SUB_GID_MIN
++	    SUB_UID_COUNT SUB_UID_MAX SUB_UID_MIN
+ 	    SYS_GID_MAX SYS_GID_MIN SYS_UID_MAX SYS_UID_MIN UID_MAX UID_MIN
+ 	    UMASK
+ 	    <phrase condition="tcb">TCB_AUTH_GROUP TCB_SYMLINK USE_TCB</phrase>
+Index: shadow/man/login.defs.d/SUB_GID_COUNT.xml
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/man/login.defs.d/SUB_GID_COUNT.xml	2013-02-01 15:27:51.044080390 -0600
+@@ -0,0 +1,46 @@
++<!--
++   Copyright (c) 2013, Eric W. Biederman
++   All rights reserved.
++  
++   Redistribution and use in source and binary forms, with or without
++   modification, are permitted provided that the following conditions
++   are met:
++   1. Redistributions of source code must retain the above copyright
++      notice, this list of conditions and the following disclaimer.
++   2. Redistributions in binary form must reproduce the above copyright
++      notice, this list of conditions and the following disclaimer in the
++      documentation and/or other materials provided with the distribution.
++   3. The name of the copyright holders or contributors may not be used to
++      endorse or promote products derived from this software without
++      specific prior written permission.
++  
++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++   HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++-->
++<varlistentry>
++  <term><option>SUB_GID_MIN</option> (number)</term>
++  <term><option>SUB_GID_MAX</option> (number)</term>
++  <term><option>SUB_GID_COUNT</option> (number)</term>
++  <listitem>
++    <para>
++      The commands <command>useradd</command> and <command>newusers</command>
++      allocate <option>SUB_GID_COUNT</option> unused group IDs from the range
++      <option>SUB_GID_MIN</option> to <option>SUB_GID_MAX</option> for each
++      new user.
++    </para>
++    <para>
++      The default values for <option>SUB_GID_MAN</option>,
++      <option>SUB_GID_MIN</option>, <option>SUB_GID_COUNT</option>
++      are respectively 100000, 600100000 and 10000.
++    </para>
++  </listitem>
++</varlistentry>
+Index: shadow/man/login.defs.d/SUB_UID_COUNT.xml
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/man/login.defs.d/SUB_UID_COUNT.xml	2013-02-01 15:27:51.044080390 -0600
+@@ -0,0 +1,46 @@
++<!--
++   Copyright (c) 2013, Eric W. Biederman
++   All rights reserved.
++  
++   Redistribution and use in source and binary forms, with or without
++   modification, are permitted provided that the following conditions
++   are met:
++   1. Redistributions of source code must retain the above copyright
++      notice, this list of conditions and the following disclaimer.
++   2. Redistributions in binary form must reproduce the above copyright
++      notice, this list of conditions and the following disclaimer in the
++      documentation and/or other materials provided with the distribution.
++   3. The name of the copyright holders or contributors may not be used to
++      endorse or promote products derived from this software without
++      specific prior written permission.
++  
++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++   HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++-->
++<varlistentry>
++  <term><option>SUB_UID_MIN</option> (number)</term>
++  <term><option>SUB_UID_MAX</option> (number)</term>
++  <term><option>SUB_UID_COUNT</option> (number)</term>
++  <listitem>
++    <para>
++      The commands <command>useradd</command> and <command>newusers</command>
++      allocate <option>SUB_UID_COUNT</option> unused user IDs from the range
++      <option>SUB_UID_MIN</option> to <option>SUB_UID_MAX</option> for each
++      new user.
++    </para>
++    <para>
++      The default values for <option>SUB_GID_MAN</option>,
++      <option>SUB_GID_MIN</option>, <option>SUB_GID_COUNT</option>
++      are respectively 100000, 600100000 and 10000.
++    </para>
++  </listitem>
++</varlistentry>
diff --git a/debian/patches/userns/03_userns_implement_commonio_append b/debian/patches/userns/03_userns_implement_commonio_append
new file mode 100644
index 0000000..b85d012
--- /dev/null
+++ b/debian/patches/userns/03_userns_implement_commonio_append
@@ -0,0 +1,110 @@
+From ebiederm at xmission.com  Tue Jan 22 09:15:19 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id CAFA8C80F6; Tue, 22 Jan 2013 09:15:19 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=0.1 required=8.0 tests=BAD_ENC_HEADER,BAYES_00
+	autolearn=no version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id 43FAEC80D1
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:15:15 +0000 (UTC)
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZvA-0006sA-Pq; Tue, 22 Jan 2013 02:13:32 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZv8-0004VI-Fi; Tue, 22 Jan 2013 02:13:32 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:13:26 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87vcapr361.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX1++0A/mQBimfZkeNedO095IfnCYGQfIolI=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 03/11] Implement commonio_append.
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2073                                                  
+Status: RO
+Content-Length: 1874
+Lines: 65
+
+
+To support files that do not have a simple unique key implement
+commonio_append to allow new entries to be added.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ lib/commonio.c |   30 ++++++++++++++++++++++++++++++
+ lib/commonio.h |    1 +
+ 2 files changed, 31 insertions(+), 0 deletions(-)
+
+Index: shadow/lib/commonio.c
+===================================================================
+--- shadow.orig/lib/commonio.c	2013-02-01 15:27:51.376080384 -0600
++++ shadow/lib/commonio.c	2013-02-01 15:27:51.368080384 -0600
+@@ -1121,6 +1121,36 @@
+ 	return 1;
+ }
+ 
++int commonio_append (struct commonio_db *db, const void *eptr)
++{
++	struct commonio_entry *p;
++	void *nentry;
++
++	if (!db->isopen || db->readonly) {
++		errno = EINVAL;
++		return 0;
++	}
++	nentry = db->ops->dup (eptr);
++	if (NULL == nentry) {
++		errno = ENOMEM;
++		return 0;
++	}
++	/* new entry */
++	p = (struct commonio_entry *) malloc (sizeof *p);
++	if (NULL == p) {
++		db->ops->free (nentry);
++		errno = ENOMEM;
++		return 0;
++	}
++
++	p->eptr = nentry;
++	p->line = NULL;
++	p->changed = true;
++	add_one_entry (db, p);
++
++	db->changed = true;
++	return 1;
++}
+ 
+ void commonio_del_entry (struct commonio_db *db, const struct commonio_entry *p)
+ {
+Index: shadow/lib/commonio.h
+===================================================================
+--- shadow.orig/lib/commonio.h	2013-02-01 15:27:51.376080384 -0600
++++ shadow/lib/commonio.h	2013-02-01 15:27:51.368080384 -0600
+@@ -146,6 +146,7 @@
+ extern int commonio_open (struct commonio_db *, int);
+ extern /*@observer@*/ /*@null@*/const void *commonio_locate (struct commonio_db *, const char *);
+ extern int commonio_update (struct commonio_db *, const void *);
++extern int commonio_append (struct commonio_db *, const void *);
+ extern int commonio_remove (struct commonio_db *, const char *);
+ extern int commonio_rewind (struct commonio_db *);
+ extern /*@observer@*/ /*@null@*/const void *commonio_next (struct commonio_db *);
diff --git a/debian/patches/userns/04_userns_add_backend_support b/debian/patches/userns/04_userns_add_backend_support
new file mode 100644
index 0000000..187b9b8
--- /dev/null
+++ b/debian/patches/userns/04_userns_add_backend_support
@@ -0,0 +1,685 @@
+From ebiederm at xmission.com  Tue Jan 22 09:16:29 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id AF9A9C80F4; Tue, 22 Jan 2013 09:16:29 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=0.1 required=8.0 tests=BAD_ENC_HEADER,BAYES_00
+	autolearn=no version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id EDF70C80D1
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:16:24 +0000 (UTC)
+Received: from out01.mta.xmission.com ([166.70.13.231])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZwI-0007HS-Mn; Tue, 22 Jan 2013 02:14:42 -0700
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out01.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZwI-0005wP-8E; Tue, 22 Jan 2013 02:14:42 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZwE-0004bA-Mv; Tue, 22 Jan 2013 02:14:42 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:14:35 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87liblr344.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX1/3QOlmT6VsAuzQbs/RJ/nb1IrpO++QYVA=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 04/11] Add backend support for suboridnate uids and gids
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2074                                                  
+Status: RO
+X-Status: A
+Content-Length: 15967
+Lines: 636
+
+
+These files list the set of subordinate uids and gids that users are allowed
+to use.   The expect use case is with the user namespace but other uses are
+allowed.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ etc/login.defs      |    8 +
+ lib/Makefile.am     |    2 +
+ lib/getdef.c        |    6 +
+ lib/subordinateio.c |  512 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ lib/subordinateio.h |   38 ++++
+ 5 files changed, 566 insertions(+), 0 deletions(-)
+ create mode 100644 lib/subordinateio.c
+ create mode 100644 lib/subordinateio.h
+
+Index: shadow/etc/login.defs
+===================================================================
+--- shadow.orig/etc/login.defs	2013-02-01 15:27:51.684080379 -0600
++++ shadow/etc/login.defs	2013-02-01 15:27:51.676080379 -0600
+@@ -226,6 +226,10 @@
+ # System accounts
+ SYS_UID_MIN		  101
+ SYS_UID_MAX		  999
++# Extra per user uids
++SUB_UID_MIN		   100000
++SUB_UID_MAX		600100000
++SUB_UID_COUNT		    10000
+ 
+ #
+ # Min/max values for automatic gid selection in groupadd
+@@ -235,6 +239,10 @@
+ # System accounts
+ SYS_GID_MIN		  101
+ SYS_GID_MAX		  999
++# Extra per user group ids
++SUB_GID_MIN		   100000
++SUB_GID_MAX		600100000
++SUB_GID_COUNT		    10000
+ 
+ #
+ # Max number of login retries if password is bad
+Index: shadow/lib/Makefile.am
+===================================================================
+--- shadow.orig/lib/Makefile.am	2013-02-01 15:27:51.684080379 -0600
++++ shadow/lib/Makefile.am	2013-02-01 15:27:51.676080379 -0600
+@@ -39,6 +39,8 @@
+ 	pwio.c \
+ 	pwio.h \
+ 	pwmem.c \
++	subordinateio.h \
++	subordinateio.c \
+ 	selinux.c \
+ 	semanage.c \
+ 	sgetgrent.c \
+Index: shadow/lib/getdef.c
+===================================================================
+--- shadow.orig/lib/getdef.c	2013-02-01 15:27:51.684080379 -0600
++++ shadow/lib/getdef.c	2013-02-01 15:27:51.680080379 -0600
+@@ -82,6 +82,12 @@
+ 	{"SHA_CRYPT_MAX_ROUNDS", NULL},
+ 	{"SHA_CRYPT_MIN_ROUNDS", NULL},
+ #endif
++	{"SUB_GID_COUNT", NULL},
++	{"SUB_GID_MAX", NULL},
++	{"SUB_GID_MIN", NULL},
++	{"SUB_UID_COUNT", NULL},
++	{"SUB_UID_MAX", NULL},
++	{"SUB_UID_MIN", NULL},
+ 	{"SULOG_FILE", NULL},
+ 	{"SU_NAME", NULL},
+ 	{"SYS_GID_MAX", NULL},
+Index: shadow/lib/subordinateio.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/lib/subordinateio.c	2013-02-01 15:27:51.680080379 -0600
+@@ -0,0 +1,512 @@
++/*
++ * Copyright (c) 2012 - Eric Biederman
++ */
++
++#include <config.h>
++#include "prototypes.h"
++#include "defines.h"
++#include <stdio.h>
++#include "commonio.h"
++#include "subordinateio.h"
++
++struct subordinate_range {
++	const char *owner;
++	unsigned long start;
++	unsigned long count;
++};
++
++#define NFIELDS 3
++
++static /*@null@*/ /*@only@*/void *subordinate_dup (const void *ent)
++{
++	const struct subordinate_range *rangeent = ent;
++	struct subordinate_range *range;
++
++	range = (struct subordinate_range *) malloc (sizeof *range);
++	if (NULL == range) {
++		return NULL;
++	}
++	range->owner = strdup (rangeent->owner);
++	if (NULL == range->owner) {
++		free(range);
++		return NULL;
++	}
++	range->start = rangeent->start;
++	range->count = rangeent->count;
++
++	return range;
++}
++
++static void subordinate_free (/*@out@*/ /*@only@*/void *ent)
++{
++	struct subordinate_range *rangeent = ent;
++	
++	free ((void *)(rangeent->owner));
++	free (rangeent);
++}
++
++static void *subordinate_parse (const char *line)
++{
++	static struct subordinate_range range;
++	char rangebuf[1024];
++	int i;
++	char *cp;
++	char *fields[NFIELDS];
++
++	/*
++	 * Copy the string to a temporary buffer so the substrings can
++	 * be modified to be NULL terminated.
++	 */
++	if (strlen (line) >= sizeof rangebuf)
++		return NULL;	/* fail if too long */
++	strcpy (rangebuf, line);
++
++	/*
++	 * Save a pointer to the start of each colon separated
++	 * field.  The fields are converted into NUL terminated strings.
++	 */
++
++	for (cp = rangebuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) {
++		fields[i] = cp;
++		while (('\0' != *cp) && (':' != *cp)) {
++			cp++;
++		}
++
++		if ('\0' != *cp) {
++			*cp = '\0';
++			cp++;
++		} else {
++			cp = NULL;
++		}
++	}
++
++	/*
++	 * There must be exactly NFIELDS colon separated fields or
++	 * the entry is invalid.  Also, fields must be non-blank.
++	 */
++	if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
++		return NULL;
++	range.owner = fields[0];
++	if (getulong (fields[1], &range.start) == 0)
++		return NULL;
++	if (getulong (fields[2], &range.count) == 0)
++		return NULL;
++
++	return ⦥
++}
++
++static int subordinate_put (const void *ent, FILE * file)
++{
++	const struct subordinate_range *range = ent;
++
++	return fprintf(file, "%s:%lu:%lu\n",
++			       range->owner,
++			       range->start,
++			       range->count) < 0 ? -1  : 0;
++}
++
++static struct commonio_ops subordinate_ops = {
++	subordinate_dup,	/* dup */
++	subordinate_free,	/* free */
++	NULL,			/* getname */
++	subordinate_parse,	/* parse */
++	subordinate_put,	/* put */
++	fgets,			/* fgets */
++	fputs,			/* fputs */
++	NULL,			/* open_hook */
++	NULL,			/* close_hook */
++};
++
++static /*@observer@*/ /*@null*/const struct subordinate_range *subordinate_next(struct commonio_db *db)
++{
++	commonio_next (db);
++}
++
++static bool is_range_free(struct commonio_db *db, unsigned long start,
++			  unsigned long count)
++{
++	const struct subordinate_range *range;
++	unsigned long end = start + count - 1;
++
++	commonio_rewind(db);
++	while ((range = commonio_next(db)) != NULL) {
++		unsigned long first = range->start;
++		unsigned long last = first + range->count - 1;
++
++		if ((end >= first) && (start <= last))
++			return false;
++	}
++	return true;
++}
++
++static const bool range_exists(struct commonio_db *db, const char *owner)
++{
++	const struct subordinate_range *range;
++	commonio_rewind(db);
++	while ((range = commonio_next(db)) != NULL) {
++		unsigned long first = range->start;
++		unsigned long last = first + range->count - 1;
++
++		if (0 == strcmp(range->owner, owner))
++			return true;
++	}
++	return false;
++}
++
++static const struct subordinate_range *find_range(struct commonio_db *db,
++						  const char *owner, unsigned long val)
++{
++	const struct subordinate_range *range;
++	commonio_rewind(db);
++	while ((range = commonio_next(db)) != NULL) {
++		unsigned long first = range->start;
++		unsigned long last = first + range->count - 1;
++
++		if (0 != strcmp(range->owner, owner))
++			continue;
++
++		if ((val >= first) && (val <= last))
++			return range;
++	}
++	return NULL;
++}
++
++static bool have_range(struct commonio_db *db,
++		       const char *owner, unsigned long start, unsigned long count)
++{
++	const struct subordinate_range *range;
++	unsigned long end;
++
++	if (count == 0)
++		return false;
++
++	end = start + count - 1;
++	range = find_range (db, owner, start);
++	while (range) {
++		unsigned long last; 
++
++		last = range->start + range->count - 1;
++		if (last >= (start + count - 1))
++			return true;
++
++		count = end - last;
++		start = last + 1;
++		range = find_range(db, owner, start);
++	}
++	return false;
++}
++
++static int subordinate_range_cmp (const void *p1, const void *p2)
++{
++	struct subordinate_range *range1, *range2;
++
++	if ((*(struct commonio_entry **) p1)->eptr == NULL)
++		return 1;
++	if ((*(struct commonio_entry **) p2)->eptr == NULL)
++		return -1;
++
++	range1 = ((struct subordinate_range *) (*(struct commonio_entry **) p1)->eptr);
++	range2 = ((struct subordinate_range *) (*(struct commonio_entry **) p2)->eptr);
++
++	if (range1->start < range2->start)
++		return -1;
++	else if (range1->start > range2->start)
++		return 1;
++	else if (range1->count < range2->count)
++		return -1;
++	else if (range1->count > range2->count)
++		return 1;
++	else
++		return strcmp(range1->owner, range2->owner);
++}
++
++static unsigned long find_free_range(struct commonio_db *db,
++				     unsigned long min, unsigned long max,
++				     unsigned long count)
++{
++	const struct subordinate_range *range;
++	unsigned long low, high;
++
++	/* When given invalid parameters fail */
++	if ((count == 0) || (max <= min))
++		goto fail;
++
++	/* Sort by range than by owner */
++	commonio_sort (db, subordinate_range_cmp);
++	commonio_rewind(db);
++
++	low = min;
++	while ((range = commonio_next(db)) != NULL) {
++		unsigned long first = range->start;
++		unsigned long last = first + range->count - 1;
++
++		/* Find the top end of the hole before this range */
++		high = first;
++		if (high > max)
++			high = max;
++
++		/* Is the hole before this range large enough? */
++		if ((high > low) && (((high - low) + 1) >= count))
++			return low;
++
++		/* Compute the low end of the next hole */
++		if (low < (last + 1))
++			low = last + 1;
++		if (low > max)
++			goto fail;
++	}
++
++	/* Is the remaining unclaimed area large enough? */
++	if (((max - low) + 1) >= count)
++		return low;
++fail:
++	return ULONG_MAX;
++}
++
++static int add_range(struct commonio_db *db,
++	const char *owner, unsigned long start, unsigned long count)
++{
++	struct subordinate_range range;
++	range.owner = owner;
++	range.start = start;
++	range.count = count;
++
++	/* See if the range is already present */
++	if (have_range(db, owner, start, count))
++		return 1;
++
++	/* Oterwise append the range */
++	return commonio_append(db, &range);
++}
++
++static int remove_range(struct commonio_db *db,
++	const char *owner, unsigned long start, unsigned long count)
++{
++	struct commonio_entry *ent;
++	unsigned long end;
++
++	if (count == 0)
++		return 1;
++
++	end = start + count - 1;
++	for (ent = db->head; ent; ent = ent->next) {
++		struct subordinate_range *range = ent->eptr;
++		unsigned long first;
++		unsigned long last;
++
++		/* Skip unparsed entries */
++		if (!range)
++			continue;
++
++		first = range->start;
++		last = first + range->count - 1;
++
++		/* Skip entries with a different owner */
++		if (0 != strcmp(range->owner, owner))
++			continue;
++
++		/* Skip entries outside of the range to remove */
++		if ((end < first) || (start > last))
++			continue;
++
++		/* Is entry completely contained in the range to remove? */
++		if ((start <= first) && (end >= last)) {
++			commonio_del_entry (db, ent);
++		} 
++		/* Is just the start of the entry removed? */
++		else if ((start <= first) && (end < last)) {
++			range->start = end + 1;
++			range->count = (last - range->start) + 1;
++
++			ent->changed = true;
++		}
++		/* Is just the end of the entry removed? */
++		else if ((start > first) && (end >= last)) {
++			range->count = (start - range->start) + 1;
++
++			ent->changed = true;
++		}
++		/* The middle of the range is removed */
++		else {
++			struct subordinate_range tail;
++			tail.owner = range->owner;
++			tail.start = end + 1;
++			tail.count = (last - tail.start) + 1;
++
++			if (!commonio_append(db, &tail))
++				return 0;
++
++			range->count = (start - range->start) + 1;
++
++			ent->changed = true;
++		}
++	}
++
++	return 1;
++}
++
++static struct commonio_db subordinate_uid_db = {
++	"/etc/subuid",		/* filename */
++	&subordinate_ops,	/* ops */
++	NULL,			/* fp */
++#ifdef WITH_SELINUX
++	NULL,			/* scontext */
++#endif
++	NULL,			/* head */
++	NULL,			/* tail */
++	NULL,			/* cursor */
++	false,			/* changed */
++	false,			/* isopen */
++	false,			/* locked */
++	false			/* readonly */
++};
++
++int sub_uid_setdbname (const char *filename)
++{
++	return commonio_setname (&subordinate_uid_db, filename);
++}
++
++/*@observer@*/const char *sub_uid_dbname (void)
++{
++	return subordinate_uid_db.filename;
++}
++
++bool sub_uid_file_present (void)
++{
++	return commonio_present (&subordinate_uid_db);
++}
++
++int sub_uid_lock (void)
++{
++	return commonio_lock (&subordinate_uid_db);
++}
++
++int sub_uid_open (int mode)
++{
++	return commonio_open (&subordinate_uid_db, mode);
++}
++
++bool is_sub_uid_range_free(uid_t start, unsigned long count)
++{
++	return is_range_free (&subordinate_uid_db, start, count);
++}
++
++bool sub_uid_assigned(const char *owner)
++{
++	return range_exists (&subordinate_uid_db, owner);
++}
++
++bool have_sub_uids(const char *owner, uid_t start, unsigned long count)
++{
++	return have_range (&subordinate_uid_db, owner, start, count);
++}
++
++int sub_uid_add (const char *owner, uid_t start, unsigned long count)
++{
++	return add_range (&subordinate_uid_db, owner, start, count);
++}
++
++int sub_uid_remove (const char *owner, uid_t start, unsigned long count)
++{
++	return remove_range (&subordinate_uid_db, owner, start, count);
++}
++
++int sub_uid_close (void)
++{
++	return commonio_close (&subordinate_uid_db);
++}
++
++int sub_uid_unlock (void)
++{
++	return commonio_unlock (&subordinate_uid_db);
++}
++
++uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count)
++{
++	unsigned long start;
++	start = find_free_range (&subordinate_uid_db, min, max, count);
++	return start == ULONG_MAX ? (uid_t) -1 : start;
++}
++
++static struct commonio_db subordinate_gid_db = {
++	"/etc/subgid",		/* filename */
++	&subordinate_ops,	/* ops */
++	NULL,			/* fp */
++#ifdef WITH_SELINUX
++	NULL,			/* scontext */
++#endif
++	NULL,			/* head */
++	NULL,			/* tail */
++	NULL,			/* cursor */
++	false,			/* changed */
++	false,			/* isopen */
++	false,			/* locked */
++	false			/* readonly */
++};
++
++int sub_gid_setdbname (const char *filename)
++{
++	return commonio_setname (&subordinate_gid_db, filename);
++}
++
++/*@observer@*/const char *sub_gid_dbname (void)
++{
++	return subordinate_gid_db.filename;
++}
++
++bool sub_gid_file_present (void)
++{
++	return commonio_present (&subordinate_gid_db);
++}
++
++int sub_gid_lock (void)
++{
++	return commonio_lock (&subordinate_gid_db);
++}
++
++int sub_gid_open (int mode)
++{
++	return commonio_open (&subordinate_gid_db, mode);
++}
++
++bool is_sub_gid_range_free(gid_t start, unsigned long count)
++{
++	return is_range_free (&subordinate_gid_db, start, count);
++}
++
++bool have_sub_gids(const char *owner, gid_t start, unsigned long count)
++{
++	return have_range(&subordinate_gid_db, owner, start, count);
++}
++
++bool sub_gid_assigned(const char *owner)
++{
++	return range_exists (&subordinate_gid_db, owner);
++}
++
++int sub_gid_add (const char *owner, gid_t start, unsigned long count)
++{
++	return add_range (&subordinate_gid_db, owner, start, count);
++}
++
++int sub_gid_remove (const char *owner, gid_t start, unsigned long count)
++{
++	return remove_range (&subordinate_gid_db, owner, start, count);
++}
++
++int sub_gid_close (void)
++{
++	return commonio_close (&subordinate_gid_db);
++}
++
++int sub_gid_unlock (void)
++{
++	return commonio_unlock (&subordinate_gid_db);
++}
++
++gid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count)
++{
++	unsigned long start;
++	start = find_free_range (&subordinate_gid_db, min, max, count);
++	return start == ULONG_MAX ? (gid_t) -1 : start;
++}
+Index: shadow/lib/subordinateio.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/lib/subordinateio.h	2013-02-01 15:27:51.680080379 -0600
+@@ -0,0 +1,38 @@
++/*
++ * Copyright (c) 2012- Eric W. Biederman
++ */
++
++#ifndef _SUBORDINATEIO_H
++#define _SUBORDINATEIO_H
++
++#include <sys/types.h>
++
++extern int sub_uid_close(void);
++extern bool is_sub_uid_range_free(uid_t start, unsigned long count);
++extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count);
++extern bool sub_uid_file_present (void);
++extern bool sub_uid_assigned(const char *owner);
++extern int sub_uid_lock (void);
++extern int sub_uid_setdbname (const char *filename);
++extern /*@observer@*/const char *sub_uid_dbname (void);
++extern int sub_uid_open (int mode);
++extern int sub_uid_unlock (void);
++extern int sub_uid_add (const char *owner, uid_t start, unsigned long count);
++extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count);
++extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count);
++
++extern int sub_gid_close(void);
++extern bool is_sub_gid_range_free(gid_t start, unsigned long count);
++extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count);
++extern bool sub_gid_file_present (void);
++extern bool sub_gid_assigned(const char *owner);
++extern int sub_gid_lock (void);
++extern int sub_gid_setdbname (const char *filename);
++extern /*@observer@*/const char *sub_gid_dbname (void);
++extern int sub_gid_open (int mode);
++extern int sub_gid_unlock (void);
++extern int sub_gid_add (const char *owner, gid_t start, unsigned long count);
++extern int sub_gid_remove (const char *owner, gid_t start, unsigned long count);
++extern uid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count);
++
++#endif
diff --git a/debian/patches/userns/05_userns_implemend_find_new_sub_xids b/debian/patches/userns/05_userns_implemend_find_new_sub_xids
new file mode 100644
index 0000000..707b552
--- /dev/null
+++ b/debian/patches/userns/05_userns_implemend_find_new_sub_xids
@@ -0,0 +1,283 @@
+From ebiederm at xmission.com  Tue Jan 22 09:17:02 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id 480ABC80F4; Tue, 22 Jan 2013 09:17:02 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=0.1 required=8.0 tests=BAD_ENC_HEADER,BAYES_00
+	autolearn=no version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id 90ACFC80D1
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:16:57 +0000 (UTC)
+Received: from out01.mta.xmission.com ([166.70.13.231])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZwp-0007cg-9X; Tue, 22 Jan 2013 02:15:15 -0700
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out01.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZwo-0006DN-OT; Tue, 22 Jan 2013 02:15:14 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZwj-0004g0-9e; Tue, 22 Jan 2013 02:15:14 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:15:05 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87fw1tr33a.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX19KHX5xUOkaLY5iIEqDVLxZKDTByyA0Xk8=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 05/11] Implement find_new_sub_uids find_new_sub_gids
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2075                                                  
+Status: RO
+Content-Length: 8108
+Lines: 235
+
+
+Functions for finding new subordinate uid and gids ranges for use
+with useradd.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ lib/prototypes.h            |    9 ++++
+ libmisc/Makefile.am         |    2 +
+ libmisc/find_new_sub_gids.c |   87 +++++++++++++++++++++++++++++++++++++++++++
+ libmisc/find_new_sub_uids.c |   87 +++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 185 insertions(+), 0 deletions(-)
+ create mode 100644 libmisc/find_new_sub_gids.c
+ create mode 100644 libmisc/find_new_sub_uids.c
+
+Index: shadow/lib/prototypes.h
+===================================================================
+--- shadow.orig/lib/prototypes.h	2013-02-01 15:27:52.044080373 -0600
++++ shadow/lib/prototypes.h	2013-02-01 15:27:52.040080373 -0600
+@@ -149,6 +149,15 @@
+                          uid_t *uid,
+                          /*@null@*/uid_t const *preferred_uid);
+ 
++/* find_new_sub_gids.c */
++extern int find_new_sub_gids (const char *owner,
++			      gid_t *range_start, unsigned long *range_count);
++
++/* find_new_sub_uids.c */
++extern int find_new_sub_uids (const char *owner,
++			      uid_t *range_start, unsigned long *range_count);
++
++
+ /* get_gid.c */
+ extern int get_gid (const char *gidstr, gid_t *gid);
+ 
+Index: shadow/libmisc/Makefile.am
+===================================================================
+--- shadow.orig/libmisc/Makefile.am	2013-02-01 15:27:52.044080373 -0600
++++ shadow/libmisc/Makefile.am	2013-02-01 15:27:52.040080373 -0600
+@@ -25,6 +25,8 @@
+ 	failure.h \
+ 	find_new_gid.c \
+ 	find_new_uid.c \
++	find_new_sub_gids.c \
++	find_new_sub_uids.c \
+ 	getdate.h \
+ 	getdate.y \
+ 	getgr_nam_gid.c \
+Index: shadow/libmisc/find_new_sub_gids.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/libmisc/find_new_sub_gids.c	2013-02-01 15:27:52.040080373 -0600
+@@ -0,0 +1,87 @@
++/*
++ * Copyright (c) 2012 Eric Biederman
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the copyright holders or contributors may not be used to
++ *    endorse or promote products derived from this software without
++ *    specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <config.h>
++
++#include <assert.h>
++#include <stdio.h>
++#include <errno.h>
++
++#include "prototypes.h"
++#include "subordinateio.h"
++#include "getdef.h"
++
++/*
++ * find_new_sub_gids - Find a new unused range of GIDs.
++ *
++ * If successful, find_new_sub_gids provides a range of unused
++ * user IDs in the [SUB_GID_MIN:SUB_GID_MAX] range.
++ * 
++ * Return 0 on success, -1 if no unused GIDs are available.
++ */
++int find_new_sub_gids (const char *owner,
++		       gid_t *range_start, unsigned long *range_count)
++{
++	unsigned long min, max;
++	unsigned long count;
++	gid_t start;
++
++	assert (range_start != NULL);
++	assert (range_count != NULL);
++
++	min = getdef_ulong ("SUB_GID_MIN", 100000UL);
++	max = getdef_ulong ("SUB_GID_MAX", 600100000UL);
++	count = getdef_ulong ("SUB_GID_COUNT", 10000);
++
++	/* Is there a preferred range that works? */
++	if ((*range_count != 0) &&
++	    (*range_start >= min) &&
++	    (((*range_start) + (*range_count) - 1) <= max) &&
++	    is_sub_gid_range_free(*range_start, *range_count)) {
++		return 0;
++	}
++
++	if (max < (min + count)) {
++		(void) fprintf (stderr,
++				_("%s: Invalid configuration: SUB_GID_MIN (%lu), SUB_GID_MAX (%lu)\n"),
++			Prog, min, max);
++		return -1;
++	}
++	start = sub_gid_find_free_range(min, max, count);
++	if (start == (gid_t)-1) {
++		fprintf (stderr,
++		         _("%s: Can't get unique secondary GID range\n"),
++		         Prog);
++		SYSLOG ((LOG_WARN, "no more available secondary GIDs on the system"));
++		return -1;
++	}
++	*range_start = start;
++	*range_count = count;
++	return 0;
++}
++
+Index: shadow/libmisc/find_new_sub_uids.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/libmisc/find_new_sub_uids.c	2013-02-01 15:27:52.040080373 -0600
+@@ -0,0 +1,87 @@
++/*
++ * Copyright (c) 2012 Eric Biederman
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the copyright holders or contributors may not be used to
++ *    endorse or promote products derived from this software without
++ *    specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <config.h>
++
++#include <assert.h>
++#include <stdio.h>
++#include <errno.h>
++
++#include "prototypes.h"
++#include "subordinateio.h"
++#include "getdef.h"
++
++/*
++ * find_new_sub_uids - Find a new unused range of UIDs.
++ *
++ * If successful, find_new_sub_uids provides a range of unused
++ * user IDs in the [SUB_UID_MIN:SUB_UID_MAX] range.
++ * 
++ * Return 0 on success, -1 if no unused UIDs are available.
++ */
++int find_new_sub_uids (const char *owner,
++		       uid_t *range_start, unsigned long *range_count)
++{
++	unsigned long min, max;
++	unsigned long count;
++	uid_t start;
++
++	assert (range_start != NULL);
++	assert (range_count != NULL);
++
++	min = getdef_ulong ("SUB_UID_MIN", 100000UL);
++	max = getdef_ulong ("SUB_UID_MAX", 600100000UL);
++	count = getdef_ulong ("SUB_UID_COUNT", 10000);
++
++	/* Is there a preferred range that works? */
++	if ((*range_count != 0) &&
++	    (*range_start >= min) &&
++	    (((*range_start) + (*range_count) - 1) <= max) &&
++	    is_sub_uid_range_free(*range_start, *range_count)) {
++		return 0;
++	}
++
++	if (max < (min + count)) {
++		(void) fprintf (stderr,
++				_("%s: Invalid configuration: SUB_UID_MIN (%lu), SUB_UID_MAX (%lu)\n"),
++			Prog, min, max);
++		return -1;
++	}
++	start = sub_uid_find_free_range(min, max, count);
++	if (start == (uid_t)-1) {
++		fprintf (stderr,
++		         _("%s: Can't get unique secondary UID range\n"),
++		         Prog);
++		SYSLOG ((LOG_WARN, "no more available secondary UIDs on the system"));
++		return -1;
++	}
++	*range_start = start;
++	*range_count = count;
++	return 0;
++}
++
diff --git a/debian/patches/userns/06_userns_userdel b/debian/patches/userns/06_userns_userdel
new file mode 100644
index 0000000..16e7051
--- /dev/null
+++ b/debian/patches/userns/06_userns_userdel
@@ -0,0 +1,236 @@
+From ebiederm at xmission.com  Tue Jan 22 09:18:47 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id F2E6AC80F6; Tue, 22 Jan 2013 09:18:46 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=0.1 required=8.0 tests=BAD_ENC_HEADER,BAYES_00
+	autolearn=no version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id 996B1C80D1
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:18:42 +0000 (UTC)
+Received: from out03.mta.xmission.com ([166.70.13.233])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZyW-0008Bi-3X; Tue, 22 Jan 2013 02:17:00 -0700
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out03.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZyU-0005NA-Qm; Tue, 22 Jan 2013 02:16:59 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZyQ-0004qs-T1; Tue, 22 Jan 2013 02:16:58 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:16:51 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <878v7lr30c.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX1/1l7dElNy9uNLAXx8eC28OMs/pxPM8NEo=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 06/11] userdel: Add support for removing subordinate user and group ids.
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2076                                        
+Status: O
+Content-Length: 5573
+Lines: 186
+
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ src/userdel.c |  115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 115 insertions(+), 0 deletions(-)
+
+Index: shadow/src/userdel.c
+===================================================================
+--- shadow.orig/src/userdel.c	2013-02-01 15:27:52.380080367 -0600
++++ shadow/src/userdel.c	2013-02-01 15:27:52.372080367 -0600
+@@ -65,6 +65,7 @@
+ #endif				/* WITH_TCB */
+ /*@-exitarg@*/
+ #include "exitcodes.h"
++#include "subordinateio.h"
+ 
+ /*
+  * exit status values
+@@ -75,6 +76,8 @@
+ #define E_GRP_UPDATE	10	/* can't update group file */
+ #define E_HOMEDIR	12	/* can't remove home directory */
+ #define E_SE_UPDATE	14	/* can't update SELinux user mapping */
++#define E_SUB_UID_UPDATE 16	/* can't update the subordinate uid file */
++#define E_SUB_GID_UPDATE 18	/* can't update the subordinate gid file */
+ 
+ /*
+  * Global variables
+@@ -96,9 +99,13 @@
+ static bool is_shadow_grp;
+ static bool sgr_locked = false;
+ #endif				/* SHADOWGRP */
++static bool is_sub_uid;
++static bool is_sub_gid;
+ static bool pw_locked  = false;
+ static bool gr_locked   = false;
+ static bool spw_locked  = false;
++static bool sub_uid_locked = false;
++static bool sub_gid_locked = false;
+ 
+ /* local function prototypes */
+ static void usage (int status);
+@@ -437,6 +444,34 @@
+ 		sgr_locked = false;
+ 	}
+ #endif				/* SHADOWGRP */
++
++	if (is_sub_uid) {
++		if (sub_uid_close () == 0) {
++			fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_uid_dbname ()));
++			fail_exit (E_SUB_UID_UPDATE);
++		}
++		if (sub_uid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
++			/* continue */
++		}
++		sub_uid_locked = false;
++	}
++
++	if (is_sub_gid) {
++		if (sub_gid_close () == 0) {
++			fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_gid_dbname ()));
++			fail_exit (E_SUB_GID_UPDATE);
++		}
++		if (sub_gid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
++			/* continue */
++		}
++		sub_gid_locked = false;
++	}
+ }
+ 
+ /*
+@@ -474,6 +509,20 @@
+ 		}
+ 	}
+ #endif				/* SHADOWGRP */
++	if (sub_uid_locked) {
++		if (sub_uid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
++			/* continue */
++		}
++	}
++	if (sub_gid_locked) {
++		if (sub_gid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
++			/* continue */
++		}
++	}
+ 
+ #ifdef WITH_AUDIT
+ 	audit_logger (AUDIT_DEL_USER, Prog,
+@@ -595,6 +644,58 @@
+ 		}
+ 	}
+ #endif				/* SHADOWGRP */
++	if (is_sub_uid) {
++		if (sub_uid_lock () == 0) {
++			fprintf (stderr,
++				_("%s: cannot lock %s; try again later.\n"),
++				Prog, sub_uid_dbname ());
++#ifdef WITH_AUDIT
++			audit_logger (AUDIT_DEL_USER, Prog,
++				"locking subordinate user file",
++				user_name, (unsigned int) user_id,
++				SHADOW_AUDIT_FAILURE);
++#endif				/* WITH_AUDIT */
++			fail_exit (E_SUB_UID_UPDATE);
++		}
++		sub_uid_locked = true;
++		if (sub_uid_open (O_RDWR) == 0) {
++			fprintf (stderr,
++				_("%s: cannot open %s\n"), Prog, sub_uid_dbname ());
++#ifdef WITH_AUDIT
++			audit_logger (AUDIT_DEL_USER, Prog,
++				"opening subordinate user file",
++				user_name, (unsigned int) user_id,
++				SHADOW_AUDIT_FAILURE);
++#endif				/* WITH_AUDIT */
++			fail_exit (E_SUB_UID_UPDATE);
++		}
++	}
++	if (is_sub_gid) {
++		if (sub_gid_lock () == 0) {
++			fprintf (stderr,
++				_("%s: cannot lock %s; try again later.\n"),
++				Prog, sub_gid_dbname ());
++#ifdef WITH_AUDIT
++			audit_logger (AUDIT_DEL_USER, Prog,
++				"locking subordinate group file",
++				user_name, (unsigned int) user_id,
++				SHADOW_AUDIT_FAILURE);
++#endif				/* WITH_AUDIT */
++			fail_exit (E_SUB_GID_UPDATE);
++		}
++		sub_gid_locked = true;
++		if (sub_gid_open (O_RDWR) == 0) {
++			fprintf (stderr,
++				_("%s: cannot open %s\n"), Prog, sub_gid_dbname ());
++#ifdef WITH_AUDIT
++			audit_logger (AUDIT_DEL_USER, Prog,
++				"opening subordinate group file",
++				user_name, (unsigned int) user_id,
++				SHADOW_AUDIT_FAILURE);
++#endif				/* WITH_AUDIT */
++			fail_exit (E_SUB_GID_UPDATE);
++		}
++	}
+ }
+ 
+ /*
+@@ -619,6 +720,18 @@
+ 		         Prog, user_name, spw_dbname ());
+ 		fail_exit (E_PW_UPDATE);
+ 	}
++	if (is_sub_uid && sub_uid_remove(user_name, 0, ULONG_MAX) == 0) {
++		fprintf (stderr,
++			_("%s: cannot remove entry %lu from %s\n"),
++			Prog, (unsigned long)user_id, sub_uid_dbname ());
++		fail_exit (E_SUB_UID_UPDATE);
++	}
++	if (is_sub_gid && sub_gid_remove(user_name, 0, ULONG_MAX) == 0) {
++		fprintf (stderr,
++			_("%s: cannot remove entry %lu from %s\n"),
++			Prog, (unsigned long)user_id, sub_gid_dbname ());
++		fail_exit (E_SUB_GID_UPDATE);
++	}
+ #ifdef WITH_AUDIT
+ 	audit_logger (AUDIT_DEL_USER, Prog,
+ 	              "deleting user entries",
+@@ -966,6 +1079,8 @@
+ #ifdef SHADOWGRP
+ 	is_shadow_grp = sgr_file_present ();
+ #endif				/* SHADOWGRP */
++	is_sub_uid = sub_uid_file_present ();
++	is_sub_gid = sub_gid_file_present ();
+ 
+ 	/*
+ 	 * Start with a quick check to see if the user exists.
diff --git a/debian/patches/userns/07_userns_useradd b/debian/patches/userns/07_userns_useradd
new file mode 100644
index 0000000..35757e9
--- /dev/null
+++ b/debian/patches/userns/07_userns_useradd
@@ -0,0 +1,285 @@
+From ebiederm at xmission.com  Tue Jan 22 09:19:29 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id 61652C80DB; Tue, 22 Jan 2013 09:19:29 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=0.1 required=8.0 tests=BAD_ENC_HEADER,BAYES_00
+	autolearn=no version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id E0ABBC80F4
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:19:23 +0000 (UTC)
+Received: from out03.mta.xmission.com ([166.70.13.233])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZzB-0008QG-Kq; Tue, 22 Jan 2013 02:17:41 -0700
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out03.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZz7-0005Ui-1H; Tue, 22 Jan 2013 02:17:37 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZz4-0004tF-BP; Tue, 22 Jan 2013 02:17:36 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:17:30 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <8738xtr2z9.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX1/Jm5H2PcjgcLXEyKh9YL3DVs2WZBJhDB8=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 07/11] useradd: Add support for subordinate user identifiers
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2077                                                  
+Status: RO
+Content-Length: 6886
+Lines: 235
+
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ src/useradd.c |  141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 140 insertions(+), 1 deletions(-)
+
+Index: shadow/src/useradd.c
+===================================================================
+--- shadow.orig/src/useradd.c	2013-02-01 15:27:52.668080362 -0600
++++ shadow/src/useradd.c	2013-02-01 15:27:52.660080362 -0600
+@@ -65,6 +65,7 @@
+ #include "sgroupio.h"
+ #endif
+ #include "shadowio.h"
++#include "subordinateio.h"
+ #ifdef WITH_TCB
+ #include "tcbfuncs.h"
+ #endif
+@@ -121,12 +122,20 @@
+ static bool is_shadow_grp;
+ static bool sgr_locked = false;
+ #endif
++static bool is_sub_uid = false;
++static bool is_sub_gid = false;
+ static bool pw_locked = false;
+ static bool gr_locked = false;
+ static bool spw_locked = false;
++static bool sub_uid_locked = false;
++static bool sub_gid_locked = false;
+ static char **user_groups;	/* NULL-terminated list */
+ static long sys_ngroups;
+ static bool do_grp_update = false;	/* group files need to be updated */
++static uid_t sub_uid_start;	/* New subordinate uid range */
++static unsigned long sub_uid_count;
++static gid_t sub_gid_start;	/* New subordinate gid range */
++static unsigned long sub_gid_count;
+ 
+ static bool
+     bflg = false,		/* new default root of home directory */
+@@ -168,6 +177,8 @@
+ #define E_GRP_UPDATE	10	/* can't update group file */
+ #define E_HOMEDIR	12	/* can't create home directory */
+ #define E_SE_UPDATE	14	/* can't update SELinux user mapping */
++#define E_SUB_UID_UPDATE 16	/* can't update the subordinate uid file */
++#define E_SUB_GID_UPDATE 18	/* can't update the subordinate gid file */
+ 
+ #define DGROUP			"GROUP="
+ #define DHOME			"HOME="
+@@ -268,6 +279,32 @@
+ 		}
+ 	}
+ #endif
++	if (sub_uid_locked) {
++		if (sub_uid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
++#ifdef WITH_AUDIT
++			audit_logger (AUDIT_ADD_USER, Prog,
++			              "unlocking subodinate user file",
++			              user_name, AUDIT_NO_ID,
++			              SHADOW_AUDIT_FAILURE);
++#endif
++			/* continue */
++		}
++	}
++	if (sub_gid_locked) {
++		if (sub_gid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
++#ifdef WITH_AUDIT
++			audit_logger (AUDIT_ADD_USER, Prog,
++			              "unlocking subodinate group file",
++			              user_name, AUDIT_NO_ID,
++			              SHADOW_AUDIT_FAILURE);
++#endif
++			/* continue */
++		}
++	}
+ 
+ #ifdef WITH_AUDIT
+ 	audit_logger (AUDIT_ADD_USER, Prog,
+@@ -1379,6 +1416,18 @@
+ 		}
+ #endif
+ 	}
++	if (is_sub_uid  && (sub_uid_close () == 0)) {
++		fprintf (stderr,
++		         _("%s: failure while writing changes to %s\n"), Prog, sub_uid_dbname ());
++		SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_uid_dbname ()));
++		fail_exit (E_SUB_UID_UPDATE);
++	}
++	if (is_sub_gid  && (sub_gid_close () == 0)) {
++		fprintf (stderr,
++		         _("%s: failure while writing changes to %s\n"), Prog, sub_gid_dbname ());
++		SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_gid_dbname ()));
++		fail_exit (E_SUB_GID_UPDATE);
++	}
+ 	if (is_shadow_pwd) {
+ 		if (spw_unlock () == 0) {
+ 			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ());
+@@ -1433,6 +1482,34 @@
+ 		sgr_locked = false;
+ 	}
+ #endif
++	if (is_sub_uid) {
++		if (sub_uid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
++#ifdef WITH_AUDIT
++			audit_logger (AUDIT_ADD_USER, Prog,
++				"unlocking subordinate user file",
++				user_name, AUDIT_NO_ID,
++				SHADOW_AUDIT_FAILURE);
++#endif
++			/* continue */
++		}
++		sub_uid_locked = false;
++	}
++	if (is_sub_gid) {
++		if (sub_gid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
++#ifdef WITH_AUDIT
++			audit_logger (AUDIT_ADD_USER, Prog,
++				"unlocking subordinate group file",
++				user_name, AUDIT_NO_ID,
++				SHADOW_AUDIT_FAILURE);
++#endif
++			/* continue */
++		}
++		sub_gid_locked = false;
++	}
+ }
+ 
+ /*
+@@ -1487,6 +1564,36 @@
+ 		}
+ 	}
+ #endif
++	if (is_sub_uid) {
++		if (sub_uid_lock () == 0) {
++			fprintf (stderr,
++			         _("%s: cannot lock %s; try again later.\n"),
++			         Prog, sub_uid_dbname ());
++			fail_exit (E_SUB_UID_UPDATE);
++		}
++		sub_uid_locked = true;
++		if (sub_uid_open (O_RDWR) == 0) {
++			fprintf (stderr,
++			         _("%s: cannot open %s\n"),
++			         Prog, sub_uid_dbname ());
++			fail_exit (E_SUB_UID_UPDATE);
++		}
++	}
++	if (is_sub_gid) {
++		if (sub_gid_lock () == 0) {
++			fprintf (stderr,
++			         _("%s: cannot lock %s; try again later.\n"),
++			         Prog, sub_gid_dbname ());
++			fail_exit (E_SUB_GID_UPDATE);
++		}
++		sub_gid_locked = true;
++		if (sub_gid_open (O_RDWR) == 0) {
++			fprintf (stderr,
++			         _("%s: cannot open %s\n"),
++			         Prog, sub_gid_dbname ());
++			fail_exit (E_SUB_GID_UPDATE);
++		}
++	}
+ }
+ 
+ static void open_shadow (void)
+@@ -1733,13 +1840,27 @@
+ #endif
+ 		fail_exit (E_PW_UPDATE);
+ 	}
++	if (is_sub_uid &&
++	    (sub_uid_add(user_name, sub_uid_start, sub_uid_count) == 0)) {
++		fprintf (stderr,
++		         _("%s: failed to prepare the new %s entry\n"),
++		         Prog, sub_uid_dbname ());
++		fail_exit (E_SUB_UID_UPDATE);
++	}
++	if (is_sub_gid &&
++	    (sub_gid_add(user_name, sub_gid_start, sub_gid_count) == 0)) {
++		fprintf (stderr,
++		         _("%s: failed to prepare the new %s entry\n"),
++		         Prog, sub_uid_dbname ());
++		fail_exit (E_SUB_GID_UPDATE);
++	}
++
+ #ifdef WITH_AUDIT
+ 	audit_logger (AUDIT_ADD_USER, Prog,
+ 	              "adding user",
+ 	              user_name, (unsigned int) user_id,
+ 	              SHADOW_AUDIT_SUCCESS);
+ #endif
+-
+ 	/*
+ 	 * Do any group file updates for this user.
+ 	 */
+@@ -1885,6 +2006,8 @@
+ #ifdef SHADOWGRP
+ 	is_shadow_grp = sgr_file_present ();
+ #endif
++	is_sub_uid = sub_uid_file_present ();
++	is_sub_gid = sub_gid_file_present ();
+ 
+ 	get_defaults ();
+ 
+@@ -2035,6 +2158,22 @@
+ 		grp_add ();
+ 	}
+ 
++	if (is_sub_uid) {
++		if (find_new_sub_uids(user_name, &sub_uid_start, &sub_uid_count) < 0) {
++			fprintf (stderr,
++				_("%s: can't find subordinate user range\n"),
++				Prog);
++			fail_exit(E_SUB_UID_UPDATE);
++		}
++	}
++	if (is_sub_gid) {
++		if (find_new_sub_gids(user_name, &sub_gid_start, &sub_gid_count) < 0) {
++			fprintf (stderr,
++				_("%s: can't find subordinate group range\n"),
++				Prog);
++			fail_exit(E_SUB_GID_UPDATE);
++		}
++	}
+ 	usr_update ();
+ 
+ 	if (mflg) {
diff --git a/debian/patches/userns/08_userns_detect_busy_subids b/debian/patches/userns/08_userns_detect_busy_subids
new file mode 100644
index 0000000..72c2862
--- /dev/null
+++ b/debian/patches/userns/08_userns_detect_busy_subids
@@ -0,0 +1,133 @@
+From ebiederm at xmission.com  Tue Jan 22 09:19:49 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id E0EA3C80F4; Tue, 22 Jan 2013 09:19:49 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=-2.2 required=8.0 tests=BAD_ENC_HEADER,BAYES_00,
+	RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id 1A2C7C80D1
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:19:46 +0000 (UTC)
+Received: from out03.mta.xmission.com ([166.70.13.233])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZzX-00006D-G7; Tue, 22 Jan 2013 02:18:03 -0700
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out03.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZzV-0005Zh-Qq; Tue, 22 Jan 2013 02:18:02 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZzN-0004ul-H6; Tue, 22 Jan 2013 02:18:01 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:17:50 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87y5flpoe9.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX1/ZWJZMWIVV2ekPIrRQjHLl4Oh/kdyWJUw=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 08/11] Add support for detecting busy subordinate user ids
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2078                                        
+Status: RO
+Content-Length: 2655
+Lines: 83
+
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ libmisc/user_busy.c |   18 +++++++++++++-----
+ 1 files changed, 13 insertions(+), 5 deletions(-)
+
+Index: shadow/libmisc/user_busy.c
+===================================================================
+--- shadow.orig/libmisc/user_busy.c	2013-02-01 15:27:52.952080357 -0600
++++ shadow/libmisc/user_busy.c	2013-02-01 15:27:52.948080357 -0600
+@@ -38,11 +38,13 @@
+ #include <stdio.h>
+ #include <sys/types.h>
+ #include <dirent.h>
++#include <fcntl.h>
+ #include "defines.h"
+ #include "prototypes.h"
++#include "subordinateio.h"
+ 
+ #ifdef __linux__
+-static int check_status (const char *sname, uid_t uid);
++static int check_status (const char *name, const char *sname, uid_t uid);
+ static int user_busy_processes (const char *name, uid_t uid);
+ #else				/* !__linux__ */
+ static int user_busy_utmp (const char *name);
+@@ -102,7 +104,7 @@
+ #endif				/* !__linux__ */
+ 
+ #ifdef __linux__
+-static int check_status (const char *sname, uid_t uid)
++static int check_status (const char *name, const char *sname, uid_t uid)
+ {
+ 	/* 40: /proc/xxxxxxxxxx/task/xxxxxxxxxx/status + \0 */
+ 	char status[40];
+@@ -125,7 +127,10 @@
+ 			            &ruid, &euid, &suid) == 3) {
+ 				if (   (ruid == (unsigned long) uid)
+ 				    || (euid == (unsigned long) uid)
+-				    || (suid == (unsigned long) uid)) {
++				    || (suid == (unsigned long) uid)
++				    || have_sub_uids(name, ruid, 1)
++				    || have_sub_uids(name, euid, 1)
++				    || have_sub_uids(name, suid, 1)) {
+ 					(void) fclose (sfile);
+ 					return 1;
+ 				}
+@@ -153,6 +158,8 @@
+ 	struct stat sbroot;
+ 	struct stat sbroot_process;
+ 
++	sub_uid_open (O_RDONLY);
++
+ 	proc = opendir ("/proc");
+ 	if (proc == NULL) {
+ 		perror ("opendir /proc");
+@@ -196,7 +203,7 @@
+ 			continue;
+ 		}
+ 
+-		if (check_status (tmp_d_name, uid) != 0) {
++		if (check_status (name, tmp_d_name, uid) != 0) {
+ 			(void) closedir (proc);
+ 			fprintf (stderr,
+ 			         _("%s: user %s is currently used by process %d\n"),
+@@ -216,7 +223,7 @@
+ 				if (tid == pid) {
+ 					continue;
+ 				}
+-				if (check_status (task_path+6, uid) != 0) {
++				if (check_status (name, task_path+6, uid) != 0) {
+ 					(void) closedir (proc);
+ 					fprintf (stderr,
+ 					         _("%s: user %s is currently used by process %d\n"),
+@@ -231,6 +238,7 @@
+ 	}
+ 
+ 	(void) closedir (proc);
++	sub_uid_close();
+ 	return 0;
+ }
+ #endif				/* __linux__ */
diff --git a/debian/patches/userns/09_userns_usermod b/debian/patches/userns/09_userns_usermod
new file mode 100644
index 0000000..2fa5493
--- /dev/null
+++ b/debian/patches/userns/09_userns_usermod
@@ -0,0 +1,536 @@
+From ebiederm at xmission.com  Tue Jan 22 09:20:27 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id 8625BC80F4; Tue, 22 Jan 2013 09:20:27 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=0.1 required=8.0 tests=BAD_ENC_HEADER,BAYES_00
+	autolearn=no version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id 69CACC80D1
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:20:23 +0000 (UTC)
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1Txa08-0000JL-Uo; Tue, 22 Jan 2013 02:18:41 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1TxZzw-0004wm-8g; Tue, 22 Jan 2013 02:18:40 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:18:24 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87sj5tpodb.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX1/EkNiL4owL54HOscHbdbK8RucFTofOBo8=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 09/11] usermod: Add support for subordinate uids and gids.
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2079                                        
+Status: O
+Content-Length: 15455
+Lines: 491
+
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ man/usermod.8.xml |   80 +++++++++++++++++
+ src/usermod.c     |  255 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 332 insertions(+), 3 deletions(-)
+
+Index: shadow/man/usermod.8.xml
+===================================================================
+--- shadow.orig/man/usermod.8.xml	2013-02-01 15:27:53.240080352 -0600
++++ shadow/man/usermod.8.xml	2013-02-01 15:27:53.232080353 -0600
+@@ -391,6 +391,86 @@
+       </varlistentry>
+       <varlistentry>
+ 	<term>
++	  <option>-v</option>, <option>--add-sub-uids</option>
++	  <replaceable>FIRST</replaceable>-<replaceable>LAST</replaceable>
++	</term>
++	<listitem>
++	  <para>
++	    Add a range of subordinate uids to the users account. 
++	  </para>
++	  <para>
++	    This option may be specified multiple times to add multiple ranges to a users account.
++	  </para>
++	  <para>
++	     No checks will be performed with regard to
++	     <option>SUB_UID_MIN</option>, <option>SUB_UID_MAX</option>, or
++	     <option>SUB_UID_COUNT</option> from /etc/login.defs.
++	  </para>
++	</listitem>
++      </varlistentry>
++      <varlistentry>
++	<term>
++	  <option>-V</option>, <option>--del-sub-uids</option>
++	  <replaceable>FIRST</replaceable>-<replaceable>LAST</replaceable>
++	</term>
++	<listitem>
++	  <para>
++	    Remove a range of subordinate uids from the users account.
++	  </para>
++	  <para>
++	    This option may be specified multiple times to remove multiple ranges to a users account.
++	    When both <option>--del-sub-uids</option> and <option>--add-sub-uids</option> are specified
++	    remove of all subordinate uid ranges happens before any subordinate uid ranges are added.
++	  </para>
++	  <para>
++	     No checks will be performed with regard to
++	     <option>SUB_UID_MIN</option>, <option>SUB_UID_MAX</option>, or
++	     <option>SUB_UID_COUNT</option> from /etc/login.defs.
++	  </para>
++	</listitem>
++      </varlistentry>
++      <varlistentry>
++	<term>
++	  <option>-w</option>, <option>--add-sub-gids</option>
++	  <replaceable>FIRST</replaceable>-<replaceable>LAST</replaceable>
++	</term>
++	<listitem>
++	  <para>
++	    Add a range of subordinate gids to the users account.
++	  </para>
++	  <para>
++	    This option may be specified multiple times to add multiple ranges to a users account.
++	  </para>
++	  <para>
++	     No checks will be performed with regard to
++	     <option>SUB_GID_MIN</option>, <option>SUB_GID_MAX</option>, or
++	     <option>SUB_GID_COUNT</option> from /etc/login.defs.
++	  </para>
++	</listitem>
++      </varlistentry>
++      <varlistentry>
++	<term>
++	  <option>-W</option>, <option>--del-sub-gids</option>
++	  <replaceable>FIRST</replaceable>-<replaceable>LAST</replaceable>
++	</term>
++	<listitem>
++	  <para>
++	    Remove a range of subordinate gids from the users account.
++	  </para>
++	  <para>
++	    This option may be specified multiple times to remove multiple ranges to a users account.
++	    When both <option>--del-sub-gids</option> and <option>--add-sub-gids</option> are specified
++	    remove of all subordinate gid ranges happens before any subordinate gid ranges are added.
++	  </para>
++	  <para>
++	     No checks will be performed with regard to
++	     <option>SUB_GID_MIN</option>, <option>SUB_GID_MAX</option>, or
++	     <option>SUB_GID_COUNT</option> from /etc/login.defs.
++	  </para>
++	</listitem>
++      </varlistentry>
++      <varlistentry>
++	<term>
+ 	  <option>-Z</option>, <option>--selinux-user</option>
+ 	  <replaceable>SEUSER</replaceable>
+ 	</term>
+Index: shadow/src/usermod.c
+===================================================================
+--- shadow.orig/src/usermod.c	2013-02-01 15:27:53.240080352 -0600
++++ shadow/src/usermod.c	2013-02-01 15:27:53.236080353 -0600
+@@ -63,6 +63,7 @@
+ #include "sgroupio.h"
+ #endif
+ #include "shadowio.h"
++#include "subordinateio.h"
+ #ifdef WITH_TCB
+ #include "tcbfuncs.h"
+ #endif
+@@ -86,6 +87,8 @@
+ /* #define E_NOSPACE	11	   insufficient space to move home dir */
+ #define E_HOMEDIR	12	/* unable to complete home dir move */
+ #define E_SE_UPDATE	13	/* can't update SELinux user mapping */
++#define E_SUB_UID_UPDATE 16	/* can't update the subordinate uid file */
++#define E_SUB_GID_UPDATE 18	/* can't update the subordinate gid file */
+ #define	VALID(s)	(strcspn (s, ":\n") == strlen (s))
+ /*
+  * Global variables
+@@ -133,7 +136,11 @@
+     Zflg = false,		/* new selinux user */
+ #endif
+     uflg = false,		/* specify new user ID */
+-    Uflg = false;		/* unlock the password */
++    Uflg = false,		/* unlock the password */
++    vflg = false,		/*    add subordinate uids */
++    Vflg = false,		/* delete subordinate uids */
++    wflg = false,		/*    add subordinate gids */
++    Wflg = false;		/* delete subordinate gids */
+ 
+ static bool is_shadow_pwd;
+ 
+@@ -141,12 +148,17 @@
+ static bool is_shadow_grp;
+ #endif
+ 
++static bool is_sub_uid = false;
++static bool is_sub_gid = false;
++
+ static bool pw_locked  = false;
+ static bool spw_locked = false;
+ static bool gr_locked  = false;
+ #ifdef SHADOWGRP
+ static bool sgr_locked = false;
+ #endif
++static bool sub_uid_locked = false;
++static bool sub_gid_locked = false;
+ 
+ 
+ /* local function prototypes */
+@@ -302,6 +314,69 @@
+ 	return 0;
+ }
+ 
++struct ulong_range
++{
++	unsigned long first;
++	unsigned long last;
++};
++
++static struct ulong_range getulong_range(const char *str)
++{
++	struct ulong_range result = { .first = ULONG_MAX, .last = 0 };
++	unsigned long long first, last;
++	char *pos;
++
++	errno = 0;
++	first = strtoll(str, &pos, 10);
++	if (('\0' == *str) || ('-' != *pos ) || (ERANGE == errno) ||
++	    (first != (unsigned long int)first))
++		goto out;
++
++	errno = 0;
++	last = strtoul(pos + 1, &pos, 10);
++	if (('\0' != *pos ) || (ERANGE == errno) ||
++	    (last != (unsigned long int)last))
++		goto out;
++
++	if (first > last)
++		goto out;
++
++	result.first = (unsigned long int)first;
++	result.last = (unsigned long int)last;
++out:
++	return result;
++	
++}
++
++struct ulong_range_list_entry {
++	struct ulong_range_list_entry *next;
++	struct ulong_range range;
++};
++
++static struct ulong_range_list_entry *add_sub_uids = NULL, *del_sub_uids = NULL;
++static struct ulong_range_list_entry *add_sub_gids = NULL, *del_sub_gids = NULL;
++
++static int prepend_range(const char *str, struct ulong_range_list_entry **head)
++{
++	struct ulong_range range;
++	struct ulong_range_list_entry *entry;
++	range = getulong_range(str);
++	if (range.first > range.last)
++		return 0;
++
++	entry = malloc(sizeof(*entry));
++	if (!entry) {
++		fprintf (stderr,
++			_("%s: failed to allocate memory: %s\n"),
++			Prog, strerror (errno));
++		return 0;
++	}
++	entry->next = *head;
++	entry->range = range;
++	*head = entry;
++	return 1;
++}
++
+ /*
+  * usage - display usage message and exit
+  */
+@@ -334,6 +409,10 @@
+ 	(void) fputs (_("  -s, --shell SHELL             new login shell for the user account\n"), usageout);
+ 	(void) fputs (_("  -u, --uid UID                 new UID for the user account\n"), usageout);
+ 	(void) fputs (_("  -U, --unlock                  unlock the user account\n"), usageout);
++	(void) fputs (_("  -v, --add-subuids FIRST-LAST  add range of subordinate uids\n"), usageout);
++	(void) fputs (_("  -V, --del-subuids FIRST-LAST  remvoe range of subordinate uids\n"), usageout);
++	(void) fputs (_("  -w, --add-subgids FIRST-LAST  add range of subordinate gids\n"), usageout);
++	(void) fputs (_("  -W, --del-subgids FIRST-LAST  remvoe range of subordinate gids\n"), usageout);
+ #ifdef WITH_SELINUX
+ 	(void) fputs (_("  -Z, --selinux-user SEUSER     new SELinux user mapping for the user account\n"), usageout);
+ #endif				/* WITH_SELINUX */
+@@ -590,6 +669,20 @@
+ 			/* continue */
+ 		}
+ 	}
++	if (sub_uid_locked) {
++		if (sub_uid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
++			/* continue */
++		}
++	}
++	if (sub_gid_locked) {
++		if (sub_gid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
++			/* continue */
++		}
++	}
+ 
+ #ifdef WITH_AUDIT
+ 	audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+@@ -889,6 +982,10 @@
+ 			{"shell",        required_argument, NULL, 's'},
+ 			{"uid",          required_argument, NULL, 'u'},
+ 			{"unlock",       no_argument,       NULL, 'U'},
++			{"add-subuids",  required_argument, NULL, 'v'},
++			{"del-subuids",  required_argument, NULL, 'V'},
++ 			{"add-subgids",  required_argument, NULL, 'w'},
++ 			{"del-subgids",  required_argument, NULL, 'W'},
+ #ifdef WITH_SELINUX
+ 			{"selinux-user", required_argument, NULL, 'Z'},
+ #endif				/* WITH_SELINUX */
+@@ -1018,6 +1115,41 @@
+ 			case 'U':
+ 				Uflg = true;
+ 				break;
++			case 'v':
++				if (prepend_range (optarg, &add_sub_uids) == 0) {
++					fprintf (stderr,
++						_("%s: invalid subordinate uid range '%s'\n"),
++						Prog, optarg);
++					exit(E_BAD_ARG);
++				}
++				vflg = true;
++				break;
++			case 'V':
++				if (prepend_range (optarg, &del_sub_uids) == 0) {
++					fprintf (stderr,
++						_("%s: invalid subordinate uid range '%s'\n"),
++						Prog, optarg);
++					exit(E_BAD_ARG);
++				}
++				Vflg = true;
++				break;
++			case 'w':
++				if (prepend_range (optarg, &add_sub_gids) == 0) {
++					fprintf (stderr,
++						_("%s: invalid subordinate gid range '%s'\n"),
++						Prog, optarg);
++					exit(E_BAD_ARG);
++				}
++				wflg = true;
++			case 'W':
++				if (prepend_range (optarg, &del_sub_gids) == 0) {
++					fprintf (stderr,
++						_("%s: invalid subordinate gid range '%s'\n"),
++						Prog, optarg);
++					exit(E_BAD_ARG);
++				}
++				Wflg = true;
++				break;
+ #ifdef WITH_SELINUX
+ 			case 'Z':
+ 				if (is_selinux_enabled () > 0) {
+@@ -1170,6 +1302,7 @@
+ 
+ 	if (!(Uflg || uflg || sflg || pflg || mflg || Lflg ||
+ 	      lflg || Gflg || gflg || fflg || eflg || dflg || cflg
++	      || vflg || Vflg || wflg || Wflg
+ #ifdef WITH_SELINUX
+ 	      || Zflg
+ #endif				/* WITH_SELINUX */
+@@ -1200,6 +1333,7 @@
+ 		         Prog, (unsigned long) user_newid);
+ 		exit (E_UID_IN_USE);
+ 	}
++
+ }
+ 
+ /*
+@@ -1248,6 +1382,10 @@
+ 				         sgr_dbname ()));
+ 				fail_exit (E_GRP_UPDATE);
+ 			}
++		}
++#endif
++#ifdef SHADOWGRP
++		if (is_shadow_grp) {
+ 			if (sgr_unlock () == 0) {
+ 				fprintf (stderr,
+ 				         _("%s: failed to unlock %s\n"),
+@@ -1296,6 +1434,33 @@
+ 	sgr_locked = false;
+ #endif
+ 
++	if (vflg || Vflg) {
++		if (!is_sub_uid || (sub_uid_close () == 0)) {
++			fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_uid_dbname ()));
++			fail_exit (E_SUB_UID_UPDATE);
++		}
++		if (!is_sub_uid || (sub_uid_unlock () == 0)) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
++			/* continue */
++		}
++		sub_uid_locked = false;
++	}
++	if (wflg || Wflg) {
++		if (!is_sub_gid || (sub_gid_close () == 0)) {
++			fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_gid_dbname ()));
++			fail_exit (E_SUB_GID_UPDATE);
++		}
++		if (!is_sub_gid || (sub_gid_unlock () == 0)) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
++			/* continue */
++		}
++		sub_gid_locked = false;
++	}
++
+ 	/*
+ 	 * Close the DBM and/or flat files
+ 	 */
+@@ -1375,6 +1540,36 @@
+ 		}
+ #endif
+ 	}
++	if (vflg || Vflg) {
++		if (!is_sub_uid || (sub_uid_lock () == 0)) {
++			fprintf (stderr,
++			         _("%s: cannot lock %s; try again later.\n"),
++			         Prog, sub_uid_dbname ());
++			fail_exit (E_SUB_UID_UPDATE);
++		}
++		sub_uid_locked = true;
++		if (!is_sub_uid || (sub_uid_open (O_RDWR) == 0)) {
++			fprintf (stderr,
++			         _("%s: cannot open %s\n"),
++			         Prog, sub_uid_dbname ());
++			fail_exit (E_SUB_UID_UPDATE);
++		}
++	}
++	if (wflg || Wflg) {
++		if (!is_sub_gid || (sub_gid_lock () == 0)) {
++			fprintf (stderr,
++			         _("%s: cannot lock %s; try again later.\n"),
++			         Prog, sub_gid_dbname ());
++			fail_exit (E_SUB_GID_UPDATE);
++		}
++		sub_gid_locked = true;
++		if (!is_sub_gid || (sub_gid_open (O_RDWR) == 0)) {
++			fprintf (stderr,
++			         _("%s: cannot open %s\n"),
++			         Prog, sub_gid_dbname ());
++			fail_exit (E_SUB_GID_UPDATE);
++		}
++	}
+ }
+ 
+ /*
+@@ -1476,6 +1671,58 @@
+ 			fail_exit (E_PW_UPDATE);
+ 		}
+ 	}
++	if (Vflg) {
++		struct ulong_range_list_entry *ptr;
++		for (ptr = del_sub_uids; ptr != NULL; ptr = ptr->next) {
++			unsigned long count = ptr->range.last - ptr->range.first + 1;
++			if (sub_uid_remove(user_name, ptr->range.first, count) == 0) {
++				fprintf (stderr,
++					_("%s: failed to remove uid range %lu-%lu from '%s'\n"),
++					Prog, ptr->range.first, ptr->range.last, 
++					sub_uid_dbname ());
++				fail_exit (E_SUB_UID_UPDATE);
++			}
++		}
++	}
++	if (vflg) {
++		struct ulong_range_list_entry *ptr;
++		for (ptr = add_sub_uids; ptr != NULL; ptr = ptr->next) {
++			unsigned long count = ptr->range.last - ptr->range.first + 1;
++			if (sub_uid_add(user_name, ptr->range.first, count) == 0) {
++				fprintf (stderr,
++					_("%s: failed to add uid range %lu-%lu from '%s'\n"),
++					Prog, ptr->range.first, ptr->range.last, 
++					sub_uid_dbname ());
++				fail_exit (E_SUB_UID_UPDATE);
++			}
++		}
++	}
++	if (Wflg) {
++		struct ulong_range_list_entry *ptr;
++		for (ptr = del_sub_gids; ptr != NULL; ptr = ptr->next) {
++			unsigned long count = ptr->range.last - ptr->range.first + 1;
++			if (sub_gid_remove(user_name, ptr->range.first, count) == 0) {
++				fprintf (stderr,
++					_("%s: failed to remove gid range %lu-%lu from '%s'\n"),
++					Prog, ptr->range.first, ptr->range.last, 
++					sub_gid_dbname ());
++				fail_exit (E_SUB_GID_UPDATE);
++			}
++		}
++	}
++	if (wflg) {
++		struct ulong_range_list_entry *ptr;
++		for (ptr = add_sub_gids; ptr != NULL; ptr = ptr->next) {
++			unsigned long count = ptr->range.last - ptr->range.first + 1;
++			if (sub_gid_add(user_name, ptr->range.first, count) == 0) {
++				fprintf (stderr,
++					_("%s: failed to add gid range %lu-%lu from '%s'\n"),
++					Prog, ptr->range.first, ptr->range.last, 
++					sub_gid_dbname ());
++				fail_exit (E_SUB_GID_UPDATE);
++			}
++		}
++	}
+ }
+ 
+ /*
+@@ -1811,6 +2058,8 @@
+ #ifdef SHADOWGRP
+ 	is_shadow_grp = sgr_file_present ();
+ #endif
++	is_sub_uid = sub_uid_file_present ();
++	is_sub_gid = sub_gid_file_present ();
+ 
+ 	process_flags (argc, argv);
+ 
+@@ -1818,7 +2067,7 @@
+ 	 * The home directory, the username and the user's UID should not
+ 	 * be changed while the user is logged in.
+ 	 */
+-	if (   (uflg || lflg || dflg)
++	if (   (uflg || lflg || dflg || Vflg || Wflg)
+ 	    && (user_busy (user_name, user_id) != 0)) {
+ 		exit (E_USER_BUSY);
+ 	}
+@@ -1871,7 +2120,7 @@
+ 	 */
+ 	open_files ();
+ 	if (   cflg || dflg || eflg || fflg || gflg || Lflg || lflg || pflg
+-	    || sflg || uflg || Uflg) {
++	    || sflg || uflg || Uflg || vflg || Vflg || wflg || Wflg) {
+ 		usr_update ();
+ 	}
+ 	if (Gflg || lflg) {
diff --git a/debian/patches/userns/10_userns_newusers b/debian/patches/userns/10_userns_newusers
new file mode 100644
index 0000000..8072cf7
--- /dev/null
+++ b/debian/patches/userns/10_userns_newusers
@@ -0,0 +1,256 @@
+From ebiederm at xmission.com  Tue Jan 22 09:21:21 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id ADE59C80F5; Tue, 22 Jan 2013 09:21:21 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=-2.2 required=8.0 tests=BAD_ENC_HEADER,BAYES_00,
+	RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id D56AEC80DB
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:21:17 +0000 (UTC)
+Received: from out03.mta.xmission.com ([166.70.13.233])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1Txa11-0000bo-MQ; Tue, 22 Jan 2013 02:19:35 -0700
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out03.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1Txa11-0005wx-1p; Tue, 22 Jan 2013 02:19:35 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1Txa0y-000519-2O; Tue, 22 Jan 2013 02:19:34 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:19:28 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87k3r5pobj.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX1+qhualZ5pxk+DVqanIJA7JrJwlPXicL8c=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 10/11] newusers: Add support for assiging subordinate uids and gids.
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2080                                        
+Status: O
+Content-Length: 5597
+Lines: 206
+
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ src/newusers.c |  124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 124 insertions(+), 0 deletions(-)
+
+Index: shadow/src/newusers.c
+===================================================================
+--- shadow.orig/src/newusers.c	2013-02-01 15:27:53.548080347 -0600
++++ shadow/src/newusers.c	2013-02-01 15:27:53.540080347 -0600
+@@ -65,6 +65,7 @@
+ #include "pwio.h"
+ #include "sgroupio.h"
+ #include "shadowio.h"
++#include "subordinateio.h"
+ #include "chkname.h"
+ 
+ /*
+@@ -82,6 +83,8 @@
+ #endif				/* USE_SHA_CRYPT */
+ #endif				/* !USE_PAM */
+ 
++static bool is_sub_uid = false;
++static bool is_sub_gid = false;
+ static bool is_shadow;
+ #ifdef SHADOWGRP
+ static bool is_shadow_grp;
+@@ -90,6 +93,8 @@
+ static bool pw_locked = false;
+ static bool gr_locked = false;
+ static bool spw_locked = false;
++static bool sub_uid_locked = false;
++static bool sub_gid_locked = false;
+ 
+ /* local function prototypes */
+ static void usage (int status);
+@@ -178,6 +183,20 @@
+ 		}
+ 	}
+ #endif
++	if (sub_uid_locked) {
++		if (sub_uid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
++			/* continue */
++		}
++	}
++	if (sub_gid_locked) {
++		if (sub_gid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
++			/* continue */
++		}
++	}
+ 
+ 	exit (code);
+ }
+@@ -732,6 +751,24 @@
+ 		sgr_locked = true;
+ 	}
+ #endif
++	if (is_sub_uid) {
++		if (sub_uid_lock () == 0) {
++			fprintf (stderr,
++			         _("%s: cannot lock %s; try again later.\n"),
++			         Prog, sub_uid_dbname ());
++			fail_exit (EXIT_FAILURE);
++		}
++		sub_uid_locked = true;
++	}
++	if (is_sub_gid) {
++		if (sub_gid_lock () == 0) {
++			fprintf (stderr,
++			         _("%s: cannot lock %s; try again later.\n"),
++			         Prog, sub_gid_dbname ());
++			fail_exit (EXIT_FAILURE);
++		}
++		sub_gid_locked = true;
++	}
+ 
+ 	if (pw_open (O_RDWR) == 0) {
+ 		fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ());
+@@ -751,6 +788,22 @@
+ 		fail_exit (EXIT_FAILURE);
+ 	}
+ #endif
++	if (is_sub_uid) {
++		if (sub_uid_open (O_RDWR) == 0) {
++			fprintf (stderr,
++			         _("%s: cannot open %s\n"),
++			         Prog, sub_uid_dbname ());
++			fail_exit (EXIT_FAILURE);
++		}
++	}
++	if (is_sub_gid) {
++		if (sub_gid_open (O_RDWR) == 0) {
++			fprintf (stderr,
++			         _("%s: cannot open %s\n"),
++			         Prog, sub_gid_dbname ());
++			fail_exit (EXIT_FAILURE);
++		}
++	}
+ }
+ 
+ /*
+@@ -795,6 +848,19 @@
+ 		SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ()));
+ 		fail_exit (EXIT_FAILURE);
+ 	}
++	if (is_sub_uid  && (sub_uid_close () == 0)) {
++		fprintf (stderr,
++		         _("%s: failure while writing changes to %s\n"), Prog, sub_uid_dbname ());
++		SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_uid_dbname ()));
++		fail_exit (EXIT_FAILURE);
++	}
++	if (is_sub_gid  && (sub_gid_close () == 0)) {
++		fprintf (stderr,
++		         _("%s: failure while writing changes to %s\n"), Prog, sub_gid_dbname ());
++		SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_gid_dbname ()));
++		fail_exit (EXIT_FAILURE);
++	}
++
+ 	if (gr_unlock () == 0) {
+ 		fprintf (stderr,
+ 		         _("%s: failed to unlock %s\n"),
+@@ -823,6 +889,22 @@
+ 		sgr_locked = false;
+ 	}
+ #endif
++	if (is_sub_uid) {
++		if (sub_uid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
++			/* continue */
++		}
++		sub_uid_locked = false;
++	}
++	if (is_sub_gid) {
++		if (sub_gid_unlock () == 0) {
++			fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
++			SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
++			/* continue */
++		}
++		sub_gid_locked = false;
++	}
+ }
+ 
+ int main (int argc, char **argv)
+@@ -864,6 +946,8 @@
+ #ifdef SHADOWGRP
+ 	is_shadow_grp = sgr_file_present ();
+ #endif
++	is_sub_uid = sub_uid_file_present ();
++	is_sub_gid = sub_gid_file_present ();
+ 
+ 	open_files ();
+ 
+@@ -1044,6 +1128,46 @@
+ 			errors++;
+ 			continue;
+ 		}
++
++		/*
++		 * Add subordinate uids if the user does not have them.
++		 */
++		if (is_sub_uid && !sub_uid_assigned(fields[0])) {
++			uid_t sub_uid_start = 0;
++			unsigned long sub_uid_count = 0;
++			if (find_new_sub_uids(fields[0], &sub_uid_start, &sub_uid_count) == 0) {
++				if (sub_uid_add(fields[0], sub_uid_start, sub_uid_count) == 0) {
++					fprintf (stderr,
++						_("%s: failed to prepare new %s entry\n"),
++						Prog, sub_uid_dbname ());
++				}
++			} else {
++				fprintf (stderr,
++					_("%s: can't find subordinate user range\n"),
++					Prog);
++				errors++;
++			}
++		}
++	
++		/*
++		 * Add subordinate gids if the user does not have them.
++		 */
++		if (is_sub_gid && !sub_gid_assigned(fields[0])) {
++			gid_t sub_gid_start = 0;
++			unsigned long sub_gid_count = 0;
++			if (find_new_sub_gids(fields[0], &sub_gid_start, &sub_gid_count) == 0) {
++				if (sub_gid_add(fields[0], sub_gid_start, sub_gid_count) == 0) {
++					fprintf (stderr,
++						_("%s: failed to prepare new %s entry\n"),
++						Prog, sub_uid_dbname ());
++				}
++			} else {
++				fprintf (stderr,
++					_("%s: can't find subordinate group range\n"),
++					Prog);
++				errors++;
++			}
++		}
+ 	}
+ 
+ 	/*
diff --git a/debian/patches/userns/11_userns_newxidmap b/debian/patches/userns/11_userns_newxidmap
new file mode 100644
index 0000000..f4e6a19
--- /dev/null
+++ b/debian/patches/userns/11_userns_newxidmap
@@ -0,0 +1,1004 @@
+From ebiederm at xmission.com  Tue Jan 22 09:22:07 2013
+Return-Path: <ebiederm at xmission.com>
+X-Original-To: serge at hallyn.com
+Delivered-To: serge at hallyn.com
+Received: by mail.hallyn.com (Postfix, from userid 5001)
+	id E5D16C80F4; Tue, 22 Jan 2013 09:22:07 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
+X-Spam-Level: 
+X-Spam-Status: No, score=-0.2 required=8.0 tests=BAD_ENC_HEADER,BAYES_00,
+	LONGWORDS,RCVD_IN_DNSWL_MED autolearn=no version=3.3.1
+Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
+	(using TLSv1 with cipher AES256-SHA (256/256 bits))
+	(No client certificate requested)
+	by mail.hallyn.com (Postfix) with ESMTPS id 2E206C80D1
+	for <serge at hallyn.com>; Tue, 22 Jan 2013 09:22:03 +0000 (UTC)
+Received: from in02.mta.xmission.com ([166.70.13.52])
+	by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1Txa1k-0000xE-Ix; Tue, 22 Jan 2013 02:20:20 -0700
+Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
+	by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
+	(Exim 4.76)
+	(envelope-from <ebiederm at xmission.com>)
+	id 1Txa1b-00059T-Lu; Tue, 22 Jan 2013 02:20:20 -0700
+From: ebiederm at xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois at centraliens.net>
+Cc: <Pkg-shadow-devel at lists.alioth.debian.org>,  Linux Containers <containers at lists.linux-foundation.org>,  "Michael Kerrisk \(man-pages\)" <mtk.manpages at gmail.com>,  "Serge E. Hallyn" <serge at hallyn.com>
+References: <87d2wxshu0.fsf at xmission.com>
+Date: Tue, 22 Jan 2013 01:20:07 -0800
+In-Reply-To: <87d2wxshu0.fsf at xmission.com> (Eric W. Biederman's message of
+	"Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87ehhdpoag.fsf at xmission.com>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
+MIME-Version: 1.0
+Content-Type: text/plain
+X-XM-AID: U2FsdGVkX1/nox3f5bDq7zL9eOiGra/HoCkv7o07HDs=
+X-SA-Exim-Connect-IP: 98.207.153.68
+X-SA-Exim-Mail-From: ebiederm at xmission.com
+Subject: [PATCH 11/11] newuidmap,newgidmap: New suid helpers for using subordinate uids and gids
+X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
+X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
+X-UID: 2081                                                  
+Status: RO
+Content-Length: 31344
+Lines: 965
+
+
+Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
+---
+ libmisc/Makefile.am |    2 +
+ libmisc/idmapping.c |  126 +++++++++++++++++++++++++++++++++++
+ libmisc/idmapping.h |   44 ++++++++++++
+ man/Makefile.am     |    4 +
+ man/newgidmap.1.xml |  157 +++++++++++++++++++++++++++++++++++++++++++
+ man/newuidmap.1.xml |  154 +++++++++++++++++++++++++++++++++++++++++++
+ src/Makefile.am     |    5 +-
+ src/newgidmap.c     |  183 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/newuidmap.c     |  183 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 9 files changed, 856 insertions(+), 2 deletions(-)
+ create mode 100644 libmisc/idmapping.c
+ create mode 100644 libmisc/idmapping.h
+ create mode 100644 man/newgidmap.1.xml
+ create mode 100644 man/newuidmap.1.xml
+ create mode 100644 src/newgidmap.c
+ create mode 100644 src/newuidmap.c
+
+Index: shadow/libmisc/Makefile.am
+===================================================================
+--- shadow.orig/libmisc/Makefile.am	2013-02-01 15:27:53.836080342 -0600
++++ shadow/libmisc/Makefile.am	2013-02-01 15:27:53.828080343 -0600
+@@ -32,6 +32,8 @@
+ 	getgr_nam_gid.c \
+ 	getrange.c \
+ 	hushed.c \
++	idmapping.h \
++	idmapping.c \
+ 	isexpired.c \
+ 	limits.c \
+ 	list.c log.c \
+Index: shadow/libmisc/idmapping.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/libmisc/idmapping.c	2013-02-01 15:27:53.828080343 -0600
+@@ -0,0 +1,126 @@
++/*
++ * Copyright (c) 2013 Eric Biederman
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the copyright holders or contributors may not be used to
++ *    endorse or promote products derived from this software without
++ *    specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <config.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <limits.h>
++#include <stdlib.h>
++#include "prototypes.h"
++#include "idmapping.h"
++
++struct map_range *get_map_ranges(int ranges, int argc, char **argv)
++{
++	struct map_range *mappings, *mapping;
++	int idx, argidx;
++
++	if ((ranges * 3) > argc) {
++		fprintf(stderr, "ranges: %u argc: %d\n",
++			ranges, argc);
++		fprintf(stderr,
++			_( "%s: Not enough arguments to form %u mappings\n"),
++			Prog, ranges);
++		return NULL;
++	}
++
++	mappings = calloc(ranges, sizeof(*mappings));
++	if (!mappings) {
++		fprintf(stderr, _( "%s: Memory allocation failure\n"),
++			Prog);
++		exit(EXIT_FAILURE);
++	}
++
++	/* Gather up the ranges from the command line */
++	mapping = mappings;
++	for (idx = 0; idx < ranges; idx++, argidx += 3, mapping++) {
++		if (!getulong(argv[argidx + 0], &mapping->upper))
++			return NULL;
++		if (!getulong(argv[argidx + 1], &mapping->lower))
++			return NULL;
++		if (!getulong(argv[argidx + 2], &mapping->count))
++			return NULL;
++	}
++	return mappings;
++}
++
++/* Number of ascii digits needed to print any unsigned long in decimal.
++ * There are approximately 10 bits for every 3 decimal digits.
++ * So from bits to digits the formula is roundup((Number of bits)/10) * 3.
++ * For common sizes of integers this works out to:
++ *  2bytes -->  6 ascii estimate  -> 65536  (5 real)
++ *  4bytes --> 12 ascii estimated -> 4294967296 (10 real)
++ *  8bytes --> 21 ascii estimated -> 18446744073709551616 (20 real)
++ * 16bytes --> 39 ascii estimated -> 340282366920938463463374607431768211456 (39 real)
++ */
++#define ULONG_DIGITS ((((sizeof(unsigned long) * CHAR_BIT) + 9)/10)*3)
++
++
++void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
++	const char *map_file)
++{
++	int idx;
++	struct map_range *mapping;
++	size_t bufsize;
++	char *buf, *pos;
++	int fd;
++
++	bufsize = ranges * ((ULONG_DIGITS  + 1) * 3);
++	pos = buf = xmalloc(bufsize);
++
++	/* Build the mapping command */
++	mapping = mappings;
++	for (idx = 0; idx < ranges; idx++, mapping++) {
++		/* Append this range to the string that will be written */
++		int written = snprintf(pos, bufsize - (pos - buf),
++			"%lu %lu %lu\n",
++			mapping->upper,
++			mapping->lower,
++			mapping->count);
++		if ((written <= 0) || (written >= (bufsize - (pos - buf)))) {
++			fprintf(stderr, _("%s: snprintf failed!\n"), Prog);
++			exit(EXIT_FAILURE);
++		}
++		pos += written;
++	}
++
++	/* Write the mapping to the maping file */
++	fd = openat(proc_dir_fd, map_file, O_WRONLY);
++	if (fd < 0) {
++		fprintf(stderr, _("%s: open of %s failed: %s\n"),
++			Prog, map_file, strerror(errno));
++		exit(EXIT_FAILURE);
++	}
++	if (write(fd, buf, pos - buf) != (pos - buf)) {
++		fprintf(stderr, _("%s: write to %s failed: %s\n"),
++			Prog, map_file, strerror(errno));
++		exit(EXIT_FAILURE);
++	}
++	close(fd);
++}
+Index: shadow/libmisc/idmapping.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/libmisc/idmapping.h	2013-02-01 15:27:53.828080343 -0600
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (c) 2013 Eric Biederman
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the copyright holders or contributors may not be used to
++ *    endorse or promote products derived from this software without
++ *    specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _IDMAPPING_H_
++#define _IDMAPPING_H_
++
++struct map_range {
++	unsigned long upper;
++	unsigned long lower;
++	unsigned long count;
++};
++
++extern struct map_range *get_map_ranges(int ranges, int argc, char **argv);
++extern void write_mapping(int proc_dir_fd, int ranges,
++	struct map_range *mappings, const char *map_file);
++
++#endif /* _ID_MAPPING_H_ */
++
+Index: shadow/man/Makefile.am
+===================================================================
+--- shadow.orig/man/Makefile.am	2013-02-01 15:27:53.836080342 -0600
++++ shadow/man/Makefile.am	2013-02-01 15:27:53.828080343 -0600
+@@ -30,7 +30,9 @@
+ 	man1/login.1 \
+ 	man5/login.defs.5 \
+ 	man8/logoutd.8 \
++	man1/newgidmap.1 \
+ 	man1/newgrp.1 \
++	man1/newuidmap.1 \
+ 	man8/newusers.8 \
+ 	man8/nologin.8 \
+ 	man1/passwd.1 \
+@@ -83,7 +85,9 @@
+ 	login.access.5.xml \
+ 	login.defs.5.xml \
+ 	logoutd.8.xml \
++	newgidmap.1.xml \
+ 	newgrp.1.xml \
++	newuidmap.1.xml \
+ 	newusers.8.xml \
+ 	nologin.8.xml \
+ 	passwd.1.xml \
+Index: shadow/man/newgidmap.1.xml
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/man/newgidmap.1.xml	2013-02-01 15:27:53.828080343 -0600
+@@ -0,0 +1,157 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!--
++   Copyright (c) 2013 Eric W. Biederman
++   All rights reserved.
++  
++   Redistribution and use in source and binary forms, with or without
++   modification, are permitted provided that the following conditions
++   are met:
++   1. Redistributions of source code must retain the above copyright
++      notice, this list of conditions and the following disclaimer.
++   2. Redistributions in binary form must reproduce the above copyright
++      notice, this list of conditions and the following disclaimer in the
++      documentation and/or other materials provided with the distribution.
++   3. The name of the copyright holders or contributors may not be used to
++      endorse or promote products derived from this software without
++      specific prior written permission.
++  
++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++   HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.5//EN"
++  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
++<!-- SHADOW-CONFIG-HERE -->
++]>
++
++<refentry id='newgidmap.1'>
++  <refmeta>
++    <refentrytitle>newgidmap</refentrytitle>
++    <manvolnum>1</manvolnum>
++    <refmiscinfo class="sectdesc">User Commands</refmiscinfo>
++    <refmiscinfo class="source">shadow-utils</refmiscinfo>
++    <refmiscinfo class="version">&SHADOW_UTILS_VERSION;</refmiscinfo>
++  </refmeta>
++  <refnamediv id='name'>
++    <refname>newgidmap</refname>
++    <refpurpose>set the gid mapping of a user namespace</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv id='synopsis'>
++    <cmdsynopsis>
++      <command>newgidmap</command>
++      <arg choice='plain'>
++	<replaceable>pid</replaceable>
++      </arg>
++      <arg choice='plain'>
++	<replaceable>gid</replaceable>
++      </arg>
++      <arg choice='plain'>
++	<replaceable>lowergid</replaceable>
++      </arg>
++      <arg choice='plain'>
++	<replaceable>count</replaceable>
++      </arg>
++      <arg choice='opt'>
++	<arg choice='plain'>
++	  <replaceable>pid</replaceable>
++	</arg>
++	<arg choice='plain'>
++	  <replaceable>gid</replaceable>
++	</arg>
++	<arg choice='plain'>
++	  <replaceable>lowergid</replaceable>
++	</arg>
++	<arg choice='plain'>
++	  <replaceable>count</replaceable>
++	</arg>
++	<arg choice='opt'>
++	  <replaceable>...</replaceable>
++	</arg>
++      </arg>
++    </cmdsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1 id='description'>
++    <title>DESCRIPTION</title>
++    <para>
++      The <command>newgidmap</command> sets <filename>/proc/[pid]/gid_map</filename> based on it's
++      command line arguments and the gids allowed in <filename>/etc/subgid</filename>.
++    </para>
++
++  </refsect1>
++
++  <refsect1 id='options'>
++    <title>OPTIONS</title>
++    <para>
++      There currently are no options to the <command>newgidmap</command> command.
++    </para>
++    <variablelist remap='IP'>
++    </variablelist>
++  </refsect1>
++
++  <refsect1 id='note'>
++    <title>NOTE</title>
++    <para>
++      The only restriction placed on the login shell is that the command
++      name must be listed in <filename>/etc/shells</filename>, unless the
++      invoker is the superuser, and then any value may be added. An
++      account with a restricted login shell may not change her login shell.
++      For this reason, placing <filename>/bin/rsh</filename> in
++      <filename>/etc/shells</filename> is discouraged since accidentally
++      changing to a restricted shell would prevent the user from ever
++      changing her login shell back to its original value.
++    </para>
++  </refsect1>
++
++
++  <refsect1 id='files'>
++    <title>FILES</title>
++    <variablelist>
++      <varlistentry>
++	<term><filename>/etc/subgid</filename></term>
++	<listitem>
++	  <para>List of users subordinate user IDs.</para>
++	</listitem>
++      </varlistentry>
++      <varlistentry>
++	<term><filename>/proc/[pid]/gid_map</filename></term>
++	<listitem>
++	  <para>Mapping of gids from one between user namespaces.</para>
++	</listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1 id='see_also'>
++    <title>SEE ALSO</title>
++    <para>
++      <citerefentry>
++	<refentrytitle>login.defs</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>useradd</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>usermod</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>newusers</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>userdel</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>subgid</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>.
++    </para>
++  </refsect1>
++</refentry>
+Index: shadow/man/newuidmap.1.xml
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/man/newuidmap.1.xml	2013-02-01 15:27:53.828080343 -0600
+@@ -0,0 +1,154 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!--
++   Copyright (c) 2013 Eric W. Biederman
++   All rights reserved.
++  
++   Redistribution and use in source and binary forms, with or without
++   modification, are permitted provided that the following conditions
++   are met:
++   1. Redistributions of source code must retain the above copyright
++      notice, this list of conditions and the following disclaimer.
++   2. Redistributions in binary form must reproduce the above copyright
++      notice, this list of conditions and the following disclaimer in the
++      documentation and/or other materials provided with the distribution.
++   3. The name of the copyright holders or contributors may not be used to
++      endorse or promote products derived from this software without
++      specific prior written permission.
++  
++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++   HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.5//EN"
++  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
++<!-- SHADOW-CONFIG-HERE -->
++]>
++
++<refentry id='newuidmap.1'>
++  <refmeta>
++    <refentrytitle>newuidmap</refentrytitle>
++    <manvolnum>1</manvolnum>
++    <refmiscinfo class="sectdesc">User Commands</refmiscinfo>
++    <refmiscinfo class="source">shadow-utils</refmiscinfo>
++    <refmiscinfo class="version">&SHADOW_UTILS_VERSION;</refmiscinfo>
++  </refmeta>
++  <refnamediv id='name'>
++    <refname>newuidmap</refname>
++    <refpurpose>set the uid mapping of a user namespace</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv id='synopsis'>
++    <cmdsynopsis>
++      <command>newuidmap</command>
++      <arg choice='plain'>
++	<replaceable>pid</replaceable>
++      </arg>
++      <arg choice='plain'>
++	<replaceable>uid</replaceable>
++      </arg>
++      <arg choice='plain'>
++	<replaceable>loweruid</replaceable>
++      </arg>
++      <arg choice='plain'>
++	<replaceable>count</replaceable>
++      </arg>
++      <arg choice='opt'>
++	<arg choice='plain'>
++	  <replaceable>uid</replaceable>
++	</arg>
++	<arg choice='plain'>
++	  <replaceable>loweruid</replaceable>
++	</arg>
++	<arg choice='plain'>
++	  <replaceable>count</replaceable>
++	</arg>
++	<arg choice='opt'>
++	  <replaceable>...</replaceable>
++	</arg>
++      </arg>
++    </cmdsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1 id='description'>
++    <title>DESCRIPTION</title>
++    <para>
++      The <command>newuidmap</command> sets <filename>/proc/[pid]/uid_map</filename> based on it's
++      command line arguments and the uids allowed in <filename>/etc/subuid</filename>.
++    </para>
++
++  </refsect1>
++
++  <refsect1 id='options'>
++    <title>OPTIONS</title>
++    <para>
++      There currently are no options to the <command>newuidmap</command> command.
++    </para>
++    <variablelist remap='IP'>
++    </variablelist>
++  </refsect1>
++
++  <refsect1 id='note'>
++    <title>NOTE</title>
++    <para>
++      The only restriction placed on the login shell is that the command
++      name must be listed in <filename>/etc/shells</filename>, unless the
++      invoker is the superuser, and then any value may be added. An
++      account with a restricted login shell may not change her login shell.
++      For this reason, placing <filename>/bin/rsh</filename> in
++      <filename>/etc/shells</filename> is discouraged since accidentally
++      changing to a restricted shell would prevent the user from ever
++      changing her login shell back to its original value.
++    </para>
++  </refsect1>
++
++
++  <refsect1 id='files'>
++    <title>FILES</title>
++    <variablelist>
++      <varlistentry>
++	<term><filename>/etc/subuid</filename></term>
++	<listitem>
++	  <para>List of users subordinate user IDs.</para>
++	</listitem>
++      </varlistentry>
++      <varlistentry>
++	<term><filename>/proc/[pid]/uid_map</filename></term>
++	<listitem>
++	  <para>Mapping of uids from one between user namespaces.</para>
++	</listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1 id='see_also'>
++    <title>SEE ALSO</title>
++    <para>
++      <citerefentry>
++	<refentrytitle>login.defs</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>useradd</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>usermod</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>newusers</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>userdel</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>subuid</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>.
++    </para>
++  </refsect1>
++</refentry>
+Index: shadow/src/Makefile.am
+===================================================================
+--- shadow.orig/src/Makefile.am	2013-02-01 15:27:53.836080342 -0600
++++ shadow/src/Makefile.am	2013-02-01 15:27:53.832080342 -0600
+@@ -23,7 +23,8 @@
+ # $prefix/bin and $prefix/sbin, no install-data hacks...)
+ 
+ bin_PROGRAMS   = groups login su
+-ubin_PROGRAMS  = faillog lastlog chage chfn chsh expiry gpasswd newgrp passwd
++ubin_PROGRAMS  = faillog lastlog chage chfn chsh expiry gpasswd newgrp passwd \
++	newgidmap newuidmap
+ usbin_PROGRAMS = \
+ 	cppw \
+ 	chgpasswd \
+@@ -50,7 +51,7 @@
+ noinst_PROGRAMS = id sulogin
+ 
+ suidbins       = su
+-suidubins      = chage chfn chsh expiry gpasswd newgrp passwd
++suidubins      = chage chfn chsh expiry gpasswd newgrp passwd newuidmap newgidmap
+ if ACCT_TOOLS_SETUID
+ 	suidubins += chage chgpasswd chpasswd groupadd groupdel groupmod newusers useradd userdel usermod
+ endif
+Index: shadow/src/newgidmap.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/src/newgidmap.c	2013-02-01 15:27:53.832080342 -0600
+@@ -0,0 +1,183 @@
++/*
++ * Copyright (c) 2013 Eric Biederman
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the copyright holders or contributors may not be used to
++ *    endorse or promote products derived from this software without
++ *    specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <config.h>
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include "defines.h"
++#include "prototypes.h"
++#include "subordinateio.h"
++#include "idmapping.h"
++
++/*
++ * Global variables
++ */
++const char *Prog;
++
++static bool verify_range(struct passwd *pw, struct map_range *range)
++{
++	/* An empty range is invalid */
++	if (range->count == 0)
++		return false;
++
++	/* Test /etc/subgid */
++	if (have_sub_gids(pw->pw_name, range->lower, range->count))
++		return true;
++
++	/* Allow a process to map it's own gid */
++	if ((range->count == 1) && (pw->pw_gid == range->lower))
++		return true;
++
++	return false;
++}
++
++static void verify_ranges(struct passwd *pw, int ranges,
++	struct map_range *mappings)
++{
++	struct map_range *mapping;
++	int idx;
++
++	mapping = mappings;
++	for (idx = 0; idx < ranges; idx++, mapping++) {
++		if (!verify_range(pw, mapping)) {
++			fprintf(stderr, _( "%s: gid range [%lu-%lu) -> [%lu-%lu) not allowed\n"),
++				Prog,
++				mapping->upper,
++				mapping->upper + mapping->count,
++				mapping->lower,
++				mapping->lower + mapping->count);
++			exit(EXIT_FAILURE);
++		}
++	}
++}
++
++static void usage(void)
++{
++	fprintf(stderr, _("usage: %s <pid> <gid> <lowergid> <count> [ <gid> <lowergid> <count> ] ... \n"), Prog);
++	exit(EXIT_FAILURE);
++}
++
++/*
++ * newgidmap - Set the gid_map for the specified process
++ */
++int main(int argc, char **argv)
++{
++	char proc_dir_name[PATH_MAX];
++	char *target_str;
++	pid_t target, parent;
++	int proc_dir_fd;
++	int ranges;
++	struct map_range *mappings;
++	struct stat st;
++	struct passwd *pw;
++	int written;
++
++	Prog = Basename (argv[0]);
++
++	/*
++	 * The valid syntax are
++	 * newgidmap target_pid
++	 */
++	if (argc < 2)
++		usage();
++
++	/* Find the process that needs it's user namespace
++	 * gid mapping set.
++	 */
++	target_str = argv[1];
++	if (!get_pid(target_str, &target))
++		usage();
++
++	written = snprintf(proc_dir_name, sizeof(proc_dir_name), "/proc/%u/",
++		target);
++	if ((written <= 0) || (written >= sizeof(proc_dir_name))) {
++		fprintf(stderr, "%s: snprintf of proc path failed: %s\n",
++			Prog, strerror(errno));
++	}
++
++	proc_dir_fd = open(proc_dir_name, O_DIRECTORY);
++	if (proc_dir_fd < 0) {
++		fprintf(stderr, _("%s: Could not open proc directory for target %u\n"),
++			Prog, target);
++		return EXIT_FAILURE;
++	}
++
++	/* Who am i? */
++	pw = get_my_pwent ();
++	if (NULL == pw) {
++		fprintf (stderr,
++			_("%s: Cannot determine your user name.\n"),
++			Prog);
++		SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
++				(unsigned long) getuid ()));
++		return EXIT_FAILURE;
++	}
++	
++	/* Get the effective uid and effective gid of the target process */
++	if (fstat(proc_dir_fd, &st) < 0) {
++		fprintf(stderr, _("%s: Could not stat directory for target %u\n"),
++			Prog, target);
++		return EXIT_FAILURE;
++	}
++
++	/* Verify real user and real group matches the password entry
++	 * and the effective user and group of the program whose
++	 * mappings we have been asked to set.
++	 */
++	if ((getuid() != pw->pw_uid) ||
++	    (getgid() != pw->pw_gid) ||
++	    (pw->pw_uid != st.st_uid) ||
++	    (pw->pw_gid != st.st_gid)) {
++		fprintf(stderr, _( "%s: Target %u is owned by a different user\n" ),
++			Prog, target);
++		return EXIT_FAILURE;
++	}
++
++	if (!sub_gid_open(O_RDONLY)) {
++		return EXIT_FAILURE;
++	}
++
++	ranges = ((argc - 2) + 2) / 3;
++	mappings = get_map_ranges(ranges, argc - 2, argv + 2);
++	if (!mappings)
++		usage();
++
++	verify_ranges(pw, ranges, mappings);
++
++	write_mapping(proc_dir_fd, ranges, mappings, "gid_map");
++	sub_gid_close();
++
++	return EXIT_SUCCESS;
++}
+Index: shadow/src/newuidmap.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ shadow/src/newuidmap.c	2013-02-01 15:27:53.832080342 -0600
+@@ -0,0 +1,183 @@
++/*
++ * Copyright (c) 2013 Eric Biederman
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the copyright holders or contributors may not be used to
++ *    endorse or promote products derived from this software without
++ *    specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
++ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <config.h>
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include "defines.h"
++#include "prototypes.h"
++#include "subordinateio.h"
++#include "idmapping.h"
++
++/*
++ * Global variables
++ */
++const char *Prog;
++
++static bool verify_range(struct passwd *pw, struct map_range *range)
++{
++	/* An empty range is invalid */
++	if (range->count == 0)
++		return false;
++
++	/* Test /etc/subuid */
++	if (have_sub_uids(pw->pw_name, range->lower, range->count))
++		return true;
++
++	/* Allow a process to map it's own uid */
++	if ((range->count == 1) && (pw->pw_uid == range->lower))
++		return true;
++
++	return false;
++}
++
++static void verify_ranges(struct passwd *pw, int ranges,
++	struct map_range *mappings)
++{
++	struct map_range *mapping;
++	int idx;
++
++	mapping = mappings;
++	for (idx = 0; idx < ranges; idx++, mapping++) {
++		if (!verify_range(pw, mapping)) {
++			fprintf(stderr, _( "%s: uid range [%lu-%lu) -> [%lu-%lu) not allowed\n"),
++				Prog,
++				mapping->upper,
++				mapping->upper + mapping->count,
++				mapping->lower,
++				mapping->lower + mapping->count);
++			exit(EXIT_FAILURE);
++		}
++	}
++}
++
++void usage(void)
++{
++	fprintf(stderr, _("usage: %s <pid> <uid> <loweruid> <count> [ <uid> <loweruid> <count> ] ... \n"), Prog);
++	exit(EXIT_FAILURE);
++}
++
++/*
++ * newuidmap - Set the uid_map for the specified process
++ */
++int main(int argc, char **argv)
++{
++	char proc_dir_name[PATH_MAX];
++	char *target_str;
++	pid_t target, parent;
++	int proc_dir_fd;
++	int ranges;
++	struct map_range *mappings;
++	struct stat st;
++	struct passwd *pw;
++	int written;
++
++	Prog = Basename (argv[0]);
++
++	/*
++	 * The valid syntax are
++	 * newuidmap target_pid
++	 */
++	if (argc < 2)
++		usage();
++
++	/* Find the process that needs it's user namespace
++	 * uid mapping set.
++	 */
++	target_str = argv[1];
++	if (!get_pid(target_str, &target))
++		usage();
++
++	written = snprintf(proc_dir_name, sizeof(proc_dir_name), "/proc/%u/",
++		target);
++	if ((written <= 0) || (written >= sizeof(proc_dir_name))) {
++		fprintf(stderr, "%s: snprintf of proc path failed: %s\n",
++			Prog, strerror(errno));
++	}
++
++	proc_dir_fd = open(proc_dir_name, O_DIRECTORY);
++	if (proc_dir_fd < 0) {
++		fprintf(stderr, _("%s: Could not open proc directory for target %u\n"),
++			Prog, target);
++		return EXIT_FAILURE;
++	}
++
++	/* Who am i? */
++	pw = get_my_pwent ();
++	if (NULL == pw) {
++		fprintf (stderr,
++			_("%s: Cannot determine your user name.\n"),
++			Prog);
++		SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
++				(unsigned long) getuid ()));
++		return EXIT_FAILURE;
++	}
++	
++	/* Get the effective uid and effective gid of the target process */
++	if (fstat(proc_dir_fd, &st) < 0) {
++		fprintf(stderr, _("%s: Could not stat directory for target %u\n"),
++			Prog, target);
++		return EXIT_FAILURE;
++	}
++
++	/* Verify real user and real group matches the password entry
++	 * and the effective user and group of the program whose
++	 * mappings we have been asked to set.
++	 */
++	if ((getuid() != pw->pw_uid) ||
++	    (getgid() != pw->pw_gid) ||
++	    (pw->pw_uid != st.st_uid) ||
++	    (pw->pw_gid != st.st_gid)) {
++		fprintf(stderr, _( "%s: Target %u is owned by a different user\n" ),
++			Prog, target);
++		return EXIT_FAILURE;
++	}
++
++	if (!sub_uid_open(O_RDONLY)) {
++		return EXIT_FAILURE;
++	}
++
++	ranges = ((argc - 2) + 2) / 3;
++	mappings = get_map_ranges(ranges, argc - 2, argv + 2);
++	if (!mappings)
++		usage();
++
++	verify_ranges(pw, ranges, mappings);
++
++	write_mapping(proc_dir_fd, ranges, mappings, "uid_map");
++	sub_uid_close();
++
++	return EXIT_SUCCESS;
++}
diff --git a/debian/patches/userns/12_userns_selinuxlibs b/debian/patches/userns/12_userns_selinuxlibs
new file mode 100644
index 0000000..71833c4
--- /dev/null
+++ b/debian/patches/userns/12_userns_selinuxlibs
@@ -0,0 +1,13 @@
+Index: shadow-4.1.5.1/src/Makefile.am
+===================================================================
+--- shadow-4.1.5.1.orig/src/Makefile.am	2013-02-04 11:56:40.485335430 -0600
++++ shadow-4.1.5.1/src/Makefile.am	2013-02-04 11:57:49.525334261 -0600
+@@ -80,6 +80,8 @@
+ endif
+ 
+ chage_LDADD    = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX)
++newuidmap_LDADD    = $(LDADD) $(LIBSELINUX)
++newgidmap_LDADD    = $(LDADD) $(LIBSELINUX)
+ chfn_LDADD     = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD)
+ chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBCRYPT)
+ chsh_LDADD     = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD)
diff --git a/debian/patches/userns/13_subordinate_parse_static_buf b/debian/patches/userns/13_subordinate_parse_static_buf
new file mode 100644
index 0000000..7c9eb3a
--- /dev/null
+++ b/debian/patches/userns/13_subordinate_parse_static_buf
@@ -0,0 +1,23 @@
+Description: subordinateio: Fix subordinate_parse to have an internal static buffer
+ subordinate_parse is supposed to return a static structure that
+ represents one line in /etc/subuid or /etc/subgid.  I goofed and
+ failed to make the variable rangebuf that holds the username of
+ in the returned structure static.
+ .
+ Add this missing static specification.
+Author: <Eric W. Biederman" <ebiederm at xmission.com>
+Origin: upstream
+Forwarded: no
+Index: shadow-4.1.5.1/lib/subordinateio.c
+===================================================================
+--- shadow-4.1.5.1.orig/lib/subordinateio.c	2013-02-04 11:56:40.265335433 -0600
++++ shadow-4.1.5.1/lib/subordinateio.c	2013-02-04 12:32:46.653298752 -0600
+@@ -48,7 +48,7 @@
+ static void *subordinate_parse (const char *line)
+ {
+ 	static struct subordinate_range range;
+-	char rangebuf[1024];
++	static char rangebuf[1024];
+ 	int i;
+ 	char *cp;
+ 	char *fields[NFIELDS];
diff --git a/debian/patches/userns/14_fix_getopt b/debian/patches/userns/14_fix_getopt
new file mode 100644
index 0000000..988e9d0
--- /dev/null
+++ b/debian/patches/userns/14_fix_getopt
@@ -0,0 +1,24 @@
+Index: shadow-userns/src/usermod.c
+===================================================================
+--- shadow-userns.orig/src/usermod.c	2013-02-05 16:35:10.608485591 +0000
++++ shadow-userns/src/usermod.c	2013-02-05 17:16:20.540485591 +0000
+@@ -993,9 +993,9 @@
+ 		};
+ 		while ((c = getopt_long (argc, argv,
+ #ifdef WITH_SELINUX
+-			                 "ac:d:e:f:g:G:hl:Lmop:R:s:u:UZ:",
++			                 "ac:d:e:f:g:G:hl:Lmop:R:s:u:UZ:v:w:V:W:",
+ #else				/* !WITH_SELINUX */
+-			                 "ac:d:e:f:g:G:hl:Lmop:R:s:u:U",
++			                 "ac:d:e:f:g:G:hl:Lmop:R:s:u:Uv:w:V:W:",
+ #endif				/* !WITH_SELINUX */
+ 			                 long_options, NULL)) != -1) {
+ 			switch (c) {
+@@ -1141,6 +1141,7 @@
+ 					exit(E_BAD_ARG);
+ 				}
+ 				wflg = true;
++                break;
+ 			case 'W':
+ 				if (prepend_range (optarg, &del_sub_gids) == 0) {
+ 					fprintf (stderr,
diff --git a/debian/patches/userns/16_add-argument-sanity-checking.patch b/debian/patches/userns/16_add-argument-sanity-checking.patch
new file mode 100644
index 0000000..d2f3515
--- /dev/null
+++ b/debian/patches/userns/16_add-argument-sanity-checking.patch
@@ -0,0 +1,80 @@
+From df3c8c1f7f47ceff607595067458f1d8e53eaab8 Mon Sep 17 00:00:00 2001
+From: Serge Hallyn <serge.hallyn at ubuntu.com>
+Date: Fri, 21 Jun 2013 11:47:36 -0500
+Subject: [PATCH 1/1] userns: add argument sanity checking
+
+In find_new_sub_{u,g}ids, check for min, count and max values.
+
+In idmapping.c:get_map_ranges(), make sure that the value passed
+in for ranges did not overflow.  Couldn't happen with the current
+code, but this is a sanity check for any future potential mis-uses.
+
+Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
+---
+ libmisc/find_new_sub_gids.c |  8 ++++++++
+ libmisc/find_new_sub_uids.c |  8 ++++++++
+ libmisc/idmapping.c         | 10 ++++++++++
+ 3 files changed, 26 insertions(+)
+
+diff --git a/libmisc/find_new_sub_gids.c b/libmisc/find_new_sub_gids.c
+index 68046ac..fd44978 100644
+--- a/libmisc/find_new_sub_gids.c
++++ b/libmisc/find_new_sub_gids.c
+@@ -58,6 +58,14 @@ int find_new_sub_gids (const char *owner,
+ 	max = getdef_ulong ("SUB_GID_MAX", 600100000UL);
+ 	count = getdef_ulong ("SUB_GID_COUNT", 10000);
+ 
++	if (min >= max || count >= max || (min + count) >= max) {
++		(void) fprintf (stderr,
++				_("%s: Invalid configuration: SUB_GID_MIN (%lu),"
++				  " SUB_GID_MAX (%lu), SUB_GID_COUNT (%lu)\n"),
++			Prog, min, max, count);
++		return -1;
++	}
++
+ 	/* Is there a preferred range that works? */
+ 	if ((*range_count != 0) &&
+ 	    (*range_start >= min) &&
+diff --git a/libmisc/find_new_sub_uids.c b/libmisc/find_new_sub_uids.c
+index f1720f9..b608c59 100644
+--- a/libmisc/find_new_sub_uids.c
++++ b/libmisc/find_new_sub_uids.c
+@@ -58,6 +58,14 @@ int find_new_sub_uids (const char *owner,
+ 	max = getdef_ulong ("SUB_UID_MAX", 600100000UL);
+ 	count = getdef_ulong ("SUB_UID_COUNT", 10000);
+ 
++	if (min >= max || count >= max || (min + count) >= max) {
++		(void) fprintf (stderr,
++				_("%s: Invalid configuration: SUB_UID_MIN (%lu),"
++				  " SUB_UID_MAX (%lu), SUB_UID_COUNT (%lu)\n"),
++			Prog, min, max, count);
++		return -1;
++	}
++
+ 	/* Is there a preferred range that works? */
+ 	if ((*range_count != 0) &&
+ 	    (*range_start >= min) &&
+diff --git a/libmisc/idmapping.c b/libmisc/idmapping.c
+index cb9e898..4147796 100644
+--- a/libmisc/idmapping.c
++++ b/libmisc/idmapping.c
+@@ -41,6 +41,16 @@ struct map_range *get_map_ranges(int ranges, int argc, char **argv)
+ 	struct map_range *mappings, *mapping;
+ 	int idx, argidx;
+ 
++	if (ranges < 0 || argc < 0) {
++		fprintf(stderr, "%s: error calculating number of arguments\n", Prog);
++		return NULL;
++	}
++
++	if (ranges != ((argc - 2) + 2) / 3) {
++		fprintf(stderr, "%s: ranges: %u is wrong for argc: %d\n", Prog, ranges, argc);
++		return NULL;
++	}
++
+ 	if ((ranges * 3) > argc) {
+ 		fprintf(stderr, "ranges: %u argc: %d\n",
+ 			ranges, argc);
+-- 
+1.8.1.2
+
diff --git a/debian/patches/userns/manpagetypo b/debian/patches/userns/manpagetypo
new file mode 100644
index 0000000..5c88585
--- /dev/null
+++ b/debian/patches/userns/manpagetypo
@@ -0,0 +1,26 @@
+Index: shadow/man/subgid.5.xml
+===================================================================
+--- shadow.orig/man/subgid.5.xml	2013-03-06 15:19:23.848386200 -0600
++++ shadow/man/subgid.5.xml	2013-03-06 15:19:51.240386816 -0600
+@@ -104,7 +104,7 @@
+ 	<refentrytitle>subuid</refentrytitle><manvolnum>5</manvolnum>
+       </citerefentry>,
+       <citerefentry>
+-	<refentrytitle>logindefs</refentrytitle><manvolnum>5</manvolnum>
++	<refentrytitle>login.defs</refentrytitle><manvolnum>5</manvolnum>
+       </citerefentry>,
+       <citerefentry>
+ 	<refentrytitle>newuidmap</refentrytitle><manvolnum>1</manvolnum>
+Index: shadow/man/subuid.5.xml
+===================================================================
+--- shadow.orig/man/subuid.5.xml	2013-03-06 15:19:09.660385881 -0600
++++ shadow/man/subuid.5.xml	2013-03-06 15:19:44.956386675 -0600
+@@ -104,7 +104,7 @@
+ 	<refentrytitle>subgid</refentrytitle><manvolnum>5</manvolnum>
+       </citerefentry>,
+       <citerefentry>
+-	<refentrytitle>logindefs</refentrytitle><manvolnum>5</manvolnum>
++	<refentrytitle>login.defs</refentrytitle><manvolnum>5</manvolnum>
+       </citerefentry>,
+       <citerefentry>
+ 	<refentrytitle>newuidmap</refentrytitle><manvolnum>1</manvolnum>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-shadow/shadow.git



More information about the Pkg-shadow-devel mailing list