diff options
author | Micah Anderson <micah@riseup.net> | 2014-02-25 22:38:58 -0500 |
---|---|---|
committer | Micah Anderson <micah@riseup.net> | 2014-02-25 23:11:31 -0500 |
commit | 13f031cd67eafa1e497cfc438ba8a3f9747a699c (patch) | |
tree | af8fa375b42eabe98ed860bbd44cb24d1f933206 | |
parent | 0c7f32eab678fa699ade9cfe70d457f54540de47 (diff) | |
download | shadow-13f031cd67eafa1e497cfc438ba8a3f9747a699c.tar.gz |
Add debian/patches/userns: patches to enable use of subuids (Closes: #739981)
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 ⦥ ++} ++ ++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> |