summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMicah Anderson <micah@riseup.net>2014-02-25 22:38:58 -0500
committerMicah Anderson <micah@riseup.net>2014-02-25 23:11:31 -0500
commit13f031cd67eafa1e497cfc438ba8a3f9747a699c (patch)
treeaf8fa375b42eabe98ed860bbd44cb24d1f933206
parent0c7f32eab678fa699ade9cfe70d457f54540de47 (diff)
downloadshadow-13f031cd67eafa1e497cfc438ba8a3f9747a699c.tar.gz
Add debian/patches/userns: patches to enable use of subuids (Closes: #739981)
-rw-r--r--debian/changelog5
-rw-r--r--debian/patches/1000_configure_userns105
-rw-r--r--debian/patches/series17
-rw-r--r--debian/patches/userns/01_userns_doc334
-rw-r--r--debian/patches/userns/02_userns_doc_login.defs218
-rw-r--r--debian/patches/userns/03_userns_implement_commonio_append110
-rw-r--r--debian/patches/userns/04_userns_add_backend_support685
-rw-r--r--debian/patches/userns/05_userns_implemend_find_new_sub_xids283
-rw-r--r--debian/patches/userns/06_userns_userdel236
-rw-r--r--debian/patches/userns/07_userns_useradd285
-rw-r--r--debian/patches/userns/08_userns_detect_busy_subids133
-rw-r--r--debian/patches/userns/09_userns_usermod536
-rw-r--r--debian/patches/userns/10_userns_newusers256
-rw-r--r--debian/patches/userns/11_userns_newxidmap1004
-rw-r--r--debian/patches/userns/12_userns_selinuxlibs13
-rw-r--r--debian/patches/userns/13_subordinate_parse_static_buf23
-rw-r--r--debian/patches/userns/14_fix_getopt24
-rw-r--r--debian/patches/userns/16_add-argument-sanity-checking.patch80
-rw-r--r--debian/patches/userns/manpagetypo26
19 files changed, 4373 insertions, 0 deletions
diff --git a/debian/changelog b/debian/changelog
index 872ed862..79cdfc3b 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@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 00000000..a198cf9e
--- /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 0a59b9f3..e3d5fee6 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 00000000..f5f5241a
--- /dev/null
+++ b/debian/patches/userns/01_userns_doc
@@ -0,0 +1,334 @@
+From ebiederm@xmission.com Tue Jan 22 09:14:18 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@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@xmission.com>)
+ id 1TxZu7-0004Pj-Ec; Tue, 22 Jan 2013 02:12:30 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:12:23 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <877gn5shs8.fsf@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@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@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 00000000..5d85cce0
--- /dev/null
+++ b/debian/patches/userns/02_userns_doc_login.defs
@@ -0,0 +1,218 @@
+From ebiederm@xmission.com Tue Jan 22 09:14:55 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@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@xmission.com>)
+ id 1TxZuf-0004T0-MS; Tue, 22 Jan 2013 02:13:07 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:12:58 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <871uddshr9.fsf@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@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@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 00000000..b85d0123
--- /dev/null
+++ b/debian/patches/userns/03_userns_implement_commonio_append
@@ -0,0 +1,110 @@
+From ebiederm@xmission.com Tue Jan 22 09:15:19 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@xmission.com>)
+ id 1TxZv8-0004VI-Fi; Tue, 22 Jan 2013 02:13:32 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:13:26 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87vcapr361.fsf@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@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@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 00000000..187b9b8c
--- /dev/null
+++ b/debian/patches/userns/04_userns_add_backend_support
@@ -0,0 +1,685 @@
+From ebiederm@xmission.com Tue Jan 22 09:16:29 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@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@xmission.com>)
+ id 1TxZwE-0004bA-Mv; Tue, 22 Jan 2013 02:14:42 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:14:35 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87liblr344.fsf@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@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@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 &range;
++}
++
++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 00000000..707b552b
--- /dev/null
+++ b/debian/patches/userns/05_userns_implemend_find_new_sub_xids
@@ -0,0 +1,283 @@
+From ebiederm@xmission.com Tue Jan 22 09:17:02 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@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@xmission.com>)
+ id 1TxZwj-0004g0-9e; Tue, 22 Jan 2013 02:15:14 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:15:05 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87fw1tr33a.fsf@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@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@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 00000000..16e7051e
--- /dev/null
+++ b/debian/patches/userns/06_userns_userdel
@@ -0,0 +1,236 @@
+From ebiederm@xmission.com Tue Jan 22 09:18:47 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@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@xmission.com>)
+ id 1TxZyQ-0004qs-T1; Tue, 22 Jan 2013 02:16:58 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:16:51 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <878v7lr30c.fsf@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@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@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 00000000..35757e9a
--- /dev/null
+++ b/debian/patches/userns/07_userns_useradd
@@ -0,0 +1,285 @@
+From ebiederm@xmission.com Tue Jan 22 09:19:29 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@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@xmission.com>)
+ id 1TxZz4-0004tF-BP; Tue, 22 Jan 2013 02:17:36 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:17:30 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <8738xtr2z9.fsf@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@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@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 00000000..72c28627
--- /dev/null
+++ b/debian/patches/userns/08_userns_detect_busy_subids
@@ -0,0 +1,133 @@
+From ebiederm@xmission.com Tue Jan 22 09:19:49 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@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@xmission.com>)
+ id 1TxZzN-0004ul-H6; Tue, 22 Jan 2013 02:18:01 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:17:50 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87y5flpoe9.fsf@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@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@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 00000000..2fa5493b
--- /dev/null
+++ b/debian/patches/userns/09_userns_usermod
@@ -0,0 +1,536 @@
+From ebiederm@xmission.com Tue Jan 22 09:20:27 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@xmission.com>)
+ id 1TxZzw-0004wm-8g; Tue, 22 Jan 2013 02:18:40 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:18:24 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87sj5tpodb.fsf@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@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@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 00000000..8072cf7a
--- /dev/null
+++ b/debian/patches/userns/10_userns_newusers
@@ -0,0 +1,256 @@
+From ebiederm@xmission.com Tue Jan 22 09:21:21 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@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@xmission.com>)
+ id 1Txa0y-000519-2O; Tue, 22 Jan 2013 02:19:34 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:19:28 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87k3r5pobj.fsf@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@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@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 00000000..f4e6a199
--- /dev/null
+++ b/debian/patches/userns/11_userns_newxidmap
@@ -0,0 +1,1004 @@
+From ebiederm@xmission.com Tue Jan 22 09:22:07 2013
+Return-Path: <ebiederm@xmission.com>
+X-Original-To: serge@hallyn.com
+Delivered-To: serge@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@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@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@xmission.com>)
+ id 1Txa1b-00059T-Lu; Tue, 22 Jan 2013 02:20:20 -0700
+From: ebiederm@xmission.com (Eric W. Biederman)
+To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
+Cc: <Pkg-shadow-devel@lists.alioth.debian.org>, Linux Containers <containers@lists.linux-foundation.org>, "Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>, "Serge E. Hallyn" <serge@hallyn.com>
+References: <87d2wxshu0.fsf@xmission.com>
+Date: Tue, 22 Jan 2013 01:20:07 -0800
+In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
+ "Tue, 22 Jan 2013 01:11:19 -0800")
+Message-ID: <87ehhdpoag.fsf@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@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@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 00000000..71833c41
--- /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 00000000..7c9eb3a9
--- /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@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 00000000..988e9d0a
--- /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 00000000..d2f35159
--- /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@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@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 00000000..5c885851
--- /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>