]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
subid: Define settings for deterministic subid ranges
authorPat Riehecky <riehecky@fnal.gov>
Mon, 30 Mar 2026 18:24:37 +0000 (13:24 -0500)
committerSerge Hallyn <serge@hallyn.com>
Fri, 10 Apr 2026 03:20:34 +0000 (22:20 -0500)
They are not active at this commit, but they are documented.

Signed-off-by: Pat Riehecky <riehecky@fnal.gov>
etc/login.defs
lib/getdef.c
man/login.defs.5.xml
man/login.defs.d/SUB_GID_COUNT.xml
man/login.defs.d/SUB_UID_COUNT.xml

index c5ff8e08382ac2d7046214087aeec84af198390f..192ea8515db71857ea6abef444bece463db09ac5 100644 (file)
@@ -244,6 +244,19 @@ SUB_UID_COUNT                  65536
 # using the numeric user ID rather than the username.
 #SUB_UID_STORE_BY_UID  no
 
+#
+# Enable deterministic subordinate UID allocation based on the user's UID.
+# When set to "yes", subordinate UID ranges are calculated using a
+# deterministic formula instead of searching for the next free range:
+#
+# WARNING: Do not mix deterministic and linear (default) allocation
+# on the same system or across systems sharing /etc/subuid. Mixing
+# methods will cause subordinate ID range conflicts and overlaps.
+#
+# Default: no
+#
+#SUB_UID_DETERMINISTIC no
+
 #
 # Min/max values for automatic gid selection in groupadd(8)
 #
@@ -261,6 +274,19 @@ SUB_GID_COUNT                  65536
 # using the numeric user ID rather than the username.
 #SUB_GID_STORE_BY_UID  no
 
+#
+# Enable deterministic subordinate GID allocation based on the user's UID.
+# When set to "yes", subordinate GID ranges are calculated using a
+# deterministic formula instead of searching for the next free range:
+#
+# WARNING: Do not mix deterministic and linear (default) allocation
+# on the same system or across systems sharing /etc/subgid. Mixing
+# methods will cause subordinate ID range conflicts and overlaps.
+#
+# Default: no
+#
+#SUB_GID_DETERMINISTIC no
+
 #
 # Max number of login(1) retries if password is bad
 #
index fa4a24d36b669875219d2ad3059475d0255d6e31..c18b05189649ed46aba1942b98ec72141549f445 100644 (file)
@@ -124,10 +124,12 @@ static struct itemdef def_table[] = {
        {"SUB_GID_COUNT", NULL},
        {"SUB_GID_MAX", NULL},
        {"SUB_GID_MIN", NULL},
+       {"SUB_GID_DETERMINISTIC", NULL},
        {"SUB_GID_STORE_BY_UID", NULL},
        {"SUB_UID_COUNT", NULL},
        {"SUB_UID_MAX", NULL},
        {"SUB_UID_MIN", NULL},
+       {"SUB_UID_DETERMINISTIC", NULL},
        {"SUB_UID_STORE_BY_UID", NULL},
        {"SULOG_FILE", NULL},
        {"SU_NAME", NULL},
index 81c39805a0d8456911f0fb68ff42cd3c0eb1e900..db258c371d83660a84a05595e2aa24bd0319b5d5 100644 (file)
@@ -5,7 +5,7 @@
    SPDX-FileCopyrightText: 2007 - 2009, Nicolas François
    SPDX-License-Identifier: BSD-3-Clause
 -->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.5//EN" 
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
 <!ENTITY BCRYPT_MIN_ROUNDS     SYSTEM "login.defs.d/BCRYPT_MIN_ROUNDS.xml">
 <!ENTITY CHFN_AUTH             SYSTEM "login.defs.d/CHFN_AUTH.xml">
       &PASS_MAX_DAYS;
       &PASS_MIN_DAYS;
       &PASS_WARN_AGE;
-      <para> 
+      <para>
         <option>PASS_MAX_DAYS</option>, <option>PASS_MIN_DAYS</option> and
         <option>PASS_WARN_AGE</option> are only used at the
         time of account creation. Any changes to these settings won't affect
       &SULOG_FILE;
       &SU_NAME;
       &SU_WHEEL_ONLY;
-      &SUB_GID_COUNT; <!-- documents also SUB_GID_MIN SUB_GID_MAX -->
+      &SUB_GID_COUNT; <!-- documents also SUB_GID_MIN SUB_GID_MAX SUB_GID_DETERMINISTIC -->
       &SUB_GID_STORE_BY_UID;
-      &SUB_UID_COUNT; <!-- documents also SUB_UID_MIN SUB_UID_MAX -->
+      &SUB_UID_COUNT; <!-- documents also SUB_UID_MIN SUB_UID_MAX SUB_UID_DETERMINISTIC -->
       &SUB_UID_STORE_BY_UID;
       &SYS_GID_MAX; <!-- documents also SYS_GID_MIN -->
       &SYS_UID_MAX; <!-- documents also SYS_UID_MIN -->
            HOME_MODE
            PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE
            SHA_CRYPT_MAX_ROUNDS SHA_CRYPT_MIN_ROUNDS
-           SUB_GID_COUNT SUB_GID_MAX SUB_GID_MIN
+           SUB_GID_COUNT SUB_GID_MAX SUB_GID_MIN SUB_GID_DETERMINISTIC
            SUB_GID_STORE_BY_UID
-           SUB_UID_COUNT SUB_UID_MAX SUB_UID_MIN
+           SUB_UID_COUNT SUB_UID_MAX SUB_UID_MIN SUB_UID_DETERMINISTIC
            SUB_UID_STORE_BY_UID
            SYS_GID_MAX SYS_GID_MIN SYS_UID_MAX SYS_UID_MIN UID_MAX UID_MIN
            UMASK
            LASTLOG_UID_MAX
            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_GID_COUNT SUB_GID_MAX SUB_GID_MIN SUB_GID_DETERMINISTIC
            SUB_GID_STORE_BY_UID
-           SUB_UID_COUNT SUB_UID_MAX SUB_UID_MIN
+           SUB_UID_COUNT SUB_UID_MAX SUB_UID_MIN SUB_UID_DETERMINISTIC
            SUB_UID_STORE_BY_UID
            SYS_GID_MAX SYS_GID_MIN SYS_UID_MAX SYS_UID_MIN UID_MAX UID_MIN
            UMASK
          <para>
            LASTLOG_UID_MAX
            MAIL_DIR MAIL_FILE MAX_MEMBERS_PER_GROUP
+           SUB_GID_COUNT SUB_GID_MAX SUB_GID_MIN SUB_GID_DETERMINISTIC
+           SUB_UID_COUNT SUB_UID_MAX SUB_UID_MIN SUB_UID_DETERMINISTIC
            <phrase condition="tcb">TCB_SYMLINKS USE_TCB</phrase>
          </para>
        </listitem>
index 4eb507831c87516f0b9cfdbeee848059807b28a1..884dc45e7120fadb661596464dc1c8014ee51108 100644 (file)
     </para>
   </listitem>
 </varlistentry>
+<varlistentry condition="subids">
+  <term><option>SUB_GID_DETERMINISTIC</option> (boolean)</term>
+  <listitem>
+    <para>
+      If set to <replaceable>yes</replaceable>,
+      the commands
+      <command>useradd</command>,
+      <command>usermod</command>,
+      and
+      <command>newusers</command>
+      will calculate subordinate GID ranges deterministically
+      based on the user's UID
+      instead of searching for the next free range.
+       The formula used is:
+    </para>
+    <literallayout>
+      start = SUB_GID_MIN + ((UID - UID_MIN) * SUB_GID_COUNT)
+      end   = start + SUB_GID_COUNT - 1
+    </literallayout>
+    <para>
+      This ensures the same UID always receives the same subordinate GID
+      range on every system,
+      making it suitable for environments with centralized user management
+      (LDAP, NIS, etc.)
+      or
+      synchronized UIDs across systems.
+    </para>
+    <para>
+      If <option>SUB_GID_DETERMINISTIC</option> is enabled,
+      you can use
+      <command>usermod --add-subgids -S</command>
+      to produce deterministic subgids.
+    </para>
+    <para>
+      <emphasis role="bold">WARNING</emphasis>:
+      Because <option>UID_MIN</option> is used to calculate the ranges,
+      any change of <option>UID_MIN</option> will change the ranges calculated.
+      <option>SUB_GID_COUNT</option> is used to calculate the ranges,
+      any change of <option>SUB_GID_COUNT</option> will change the ranges calculated.
+      Users with identities less than <option>UID_MIN</option>
+      are incompatible with <option>SUB_GID_DETERMINISTIC</option>,
+      but can still be set manually.
+    </para>
+    <para>
+      <emphasis role="bold">WARNING</emphasis>:
+      Do not mix deterministic and linear (default) allocation on the same system
+      or across systems sharing <filename>/etc/subgid</filename>
+      via network storage (NFS, etc.).
+      Mixing allocation methods
+      <emphasis role="bold">
+      will cause subordinate ID range conflicts and overlaps
+      </emphasis>.
+    </para>
+    <para>
+      The default value for <option>SUB_GID_DETERMINISTIC</option> is
+      <replaceable>no</replaceable>.
+    </para>
+    <refsect2>
+      <title>Range Calculation Examples</title>
+      <para>
+        With default configuration
+        (<option>UID_MIN</option>=1000,
+        <option>SUB_GID_MIN</option>=100000,
+        <option>SUB_GID_COUNT</option>=65536):
+      </para>
+      <informaltable>
+        <tgroup cols="3">
+          <thead>
+            <row>
+              <entry>UID</entry>
+              <entry>Calculation</entry>
+              <entry>Subordinate GID Range</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>1000</entry>
+              <entry>100000 + ((1000-1000) * 65536)</entry>
+              <entry>100000-165535</entry>
+            </row>
+            <row>
+              <entry>1001</entry>
+              <entry>100000 + ((1001-1000) * 65536)</entry>
+              <entry>165536-231071</entry>
+            </row>
+            <row>
+              <entry>1002</entry>
+              <entry>100000 + ((1002-1000) * 65536)</entry>
+              <entry>231072-296607</entry>
+            </row>
+            <row>
+              <entry>1100</entry>
+              <entry>100000 + ((1100-1000) * 65536)</entry>
+              <entry>6653600-6719135</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </informaltable>
+    </refsect2>
+    <refsect2>
+      <title>Subordinate ID Space Planning</title>
+      <para>
+        When planning subordinate ID allocation,
+        calculate the maximum number of users the space can accommodate:
+      </para>
+      <literallayout>
+      capacity = (SUB_GID_MAX - SUB_GID_MIN) / SUB_GID_COUNT
+      </literallayout>
+      <para>
+        With default values: (600100000 - 100000) / 65536 ≈ 9155 users.
+      </para>
+      <para>
+        For high-density environments with many users and smaller allocations:
+      </para>
+      <literallayout>
+        SUB_GID_COUNT  4096
+        SUB_GID_MIN    100000
+        SUB_GID_MAX    10000000
+      </literallayout>
+      <para>
+        This gives: (10000000 - 100000) / 4096 ≈ 2417 users.
+      </para>
+    </refsect2>
+  </listitem>
+</varlistentry>
index 90bead5e77f78f833e562ee3f893af2a9c73ac41..15e9fb7a84f5b3214c1624263071610b07f0f10d 100644 (file)
     </para>
   </listitem>
 </varlistentry>
+<varlistentry condition="subids">
+  <term><option>SUB_UID_DETERMINISTIC</option> (boolean)</term>
+  <listitem>
+    <para>
+      If set to <replaceable>yes</replaceable>,
+      the commands
+      <command>useradd</command>,
+      <command>usermod</command>,
+      and
+      <command>newusers</command>
+      will calculate subordinate UID ranges deterministically
+      based on the user's UID
+      instead of searching for the next free range.
+       The formula used is:
+    </para>
+    <literallayout>
+      start = SUB_UID_MIN + ((UID - UID_MIN) * SUB_UID_COUNT)
+      end   = start + SUB_UID_COUNT - 1
+    </literallayout>
+    <para>
+      This ensures the same UID always receives the same subordinate UID
+      range on every system,
+      making it suitable for environments with centralized user management
+      (LDAP, NIS, etc.)
+      or
+      synchronized UIDs across systems.
+    </para>
+    <para>
+      If <option>SUB_UID_DETERMINISTIC</option> is enabled,
+      you can use
+      <command>usermod --add-subuids -S</command>
+      to produce deterministic subuids.
+    </para>
+    <para>
+      <emphasis role="bold">WARNING</emphasis>:
+      Because <option>UID_MIN</option> is used to calculate the ranges,
+      any change of <option>UID_MIN</option> will change the ranges calculated.
+      <option>SUB_UID_COUNT</option> is used to calculate the ranges,
+      any change of <option>SUB_UID_COUNT</option> will change the ranges calculated.
+      Users with identities less than <option>UID_MIN</option>
+      are incompatible with <option>SUB_UID_DETERMINISTIC</option>,
+      but can still be set manually.
+    </para>
+    <para>
+      <emphasis role="bold">WARNING</emphasis>:
+      Do not mix deterministic and linear (default) allocation on the same system
+      or across systems sharing <filename>/etc/subuid</filename>
+      via network storage (NFS, etc.).
+      Mixing allocation methods
+      <emphasis role="bold">
+      will cause subordinate ID range conflicts and overlaps
+      </emphasis>.
+    </para>
+    <para>
+      The default value for <option>SUB_UID_DETERMINISTIC</option> is
+      <replaceable>no</replaceable>.
+    </para>
+    <refsect2>
+      <title>Range Calculation Examples</title>
+      <para>
+        With default configuration
+        (<option>UID_MIN</option>=1000,
+        <option>SUB_UID_MIN</option>=100000,
+        <option>SUB_UID_COUNT</option>=65536):
+      </para>
+      <informaltable>
+        <tgroup cols="3">
+          <thead>
+            <row>
+              <entry>UID</entry>
+              <entry>Calculation</entry>
+              <entry>Subordinate UID Range</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>1000</entry>
+              <entry>100000 + ((1000-1000) * 65536)</entry>
+              <entry>100000-165535</entry>
+            </row>
+            <row>
+              <entry>1001</entry>
+              <entry>100000 + ((1001-1000) * 65536)</entry>
+              <entry>165536-231071</entry>
+            </row>
+            <row>
+              <entry>1002</entry>
+              <entry>100000 + ((1002-1000) * 65536)</entry>
+              <entry>231072-296607</entry>
+            </row>
+            <row>
+              <entry>1100</entry>
+              <entry>100000 + ((1100-1000) * 65536)</entry>
+              <entry>6653600-6719135</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </informaltable>
+    </refsect2>
+    <refsect2>
+      <title>Subordinate ID Space Planning</title>
+      <para>
+        When planning subordinate ID allocation,
+        calculate the maximum number of users the space can accommodate:
+      </para>
+      <literallayout>
+      capacity = (SUB_UID_MAX - SUB_UID_MIN) / SUB_UID_COUNT
+      </literallayout>
+      <para>
+        With default values: (600100000 - 100000) / 65536 ≈ 9155 users.
+      </para>
+      <para>
+        For high-density environments with many users and smaller allocations:
+      </para>
+      <literallayout>
+        SUB_UID_COUNT  4096
+        SUB_UID_MIN    100000
+        SUB_UID_MAX    10000000
+      </literallayout>
+      <para>
+        This gives: (10000000 - 100000) / 4096 ≈ 2417 users.
+      </para>
+    </refsect2>
+  </listitem>
+</varlistentry>