~serge-hallyn/ubuntu/raring/shadow/shadow-userns

« back to all changes in this revision

Viewing changes to debian/patches/userns/09_userns_usermod

  • Committer: Serge Hallyn
  • Date: 2013-02-01 21:31:48 UTC
  • Revision ID: serge.hallyn@canonical.com-20130201213148-6ms9125tjn2lngnq
Add patchset by Eric Biederman to support subids for use by unprivileged
users to administer private user namespaces.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
From ebiederm@xmission.com  Tue Jan 22 09:20:27 2013
 
2
Return-Path: <ebiederm@xmission.com>
 
3
X-Original-To: serge@hallyn.com
 
4
Delivered-To: serge@hallyn.com
 
5
Received: by mail.hallyn.com (Postfix, from userid 5001)
 
6
        id 8625BC80F4; Tue, 22 Jan 2013 09:20:27 +0000 (UTC)
 
7
X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail
 
8
X-Spam-Level: 
 
9
X-Spam-Status: No, score=0.1 required=8.0 tests=BAD_ENC_HEADER,BAYES_00
 
10
        autolearn=no version=3.3.1
 
11
Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232])
 
12
        (using TLSv1 with cipher AES256-SHA (256/256 bits))
 
13
        (No client certificate requested)
 
14
        by mail.hallyn.com (Postfix) with ESMTPS id 69CACC80D1
 
15
        for <serge@hallyn.com>; Tue, 22 Jan 2013 09:20:23 +0000 (UTC)
 
16
Received: from in02.mta.xmission.com ([166.70.13.52])
 
17
        by out02.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
 
18
        (Exim 4.76)
 
19
        (envelope-from <ebiederm@xmission.com>)
 
20
        id 1Txa08-0000JL-Uo; Tue, 22 Jan 2013 02:18:41 -0700
 
21
Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
 
22
        by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
 
23
        (Exim 4.76)
 
24
        (envelope-from <ebiederm@xmission.com>)
 
25
        id 1TxZzw-0004wm-8g; Tue, 22 Jan 2013 02:18:40 -0700
 
26
From: ebiederm@xmission.com (Eric W. Biederman)
 
27
To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
 
28
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>
 
29
References: <87d2wxshu0.fsf@xmission.com>
 
30
Date: Tue, 22 Jan 2013 01:18:24 -0800
 
31
In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
 
32
        "Tue, 22 Jan 2013 01:11:19 -0800")
 
33
Message-ID: <87sj5tpodb.fsf@xmission.com>
 
34
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
 
35
MIME-Version: 1.0
 
36
Content-Type: text/plain
 
37
X-XM-AID: U2FsdGVkX1/EkNiL4owL54HOscHbdbK8RucFTofOBo8=
 
38
X-SA-Exim-Connect-IP: 98.207.153.68
 
39
X-SA-Exim-Mail-From: ebiederm@xmission.com
 
40
Subject: [PATCH 09/11] usermod: Add support for subordinate uids and gids.
 
41
X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
 
42
X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
 
43
X-UID: 2079                                        
 
44
Status: O
 
45
Content-Length: 15455
 
46
Lines: 491
 
47
 
 
48
 
 
49
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
 
50
---
 
51
 man/usermod.8.xml |   80 +++++++++++++++++
 
52
 src/usermod.c     |  255 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 
53
 2 files changed, 332 insertions(+), 3 deletions(-)
 
54
 
 
55
Index: shadow/man/usermod.8.xml
 
56
===================================================================
 
57
--- shadow.orig/man/usermod.8.xml       2013-02-01 15:27:53.240080352 -0600
 
58
+++ shadow/man/usermod.8.xml    2013-02-01 15:27:53.232080353 -0600
 
59
@@ -391,6 +391,86 @@
 
60
       </varlistentry>
 
61
       <varlistentry>
 
62
        <term>
 
63
+         <option>-v</option>, <option>--add-sub-uids</option>
 
64
+         <replaceable>FIRST</replaceable>-<replaceable>LAST</replaceable>
 
65
+       </term>
 
66
+       <listitem>
 
67
+         <para>
 
68
+           Add a range of subordinate uids to the users account. 
 
69
+         </para>
 
70
+         <para>
 
71
+           This option may be specified multiple times to add multiple ranges to a users account.
 
72
+         </para>
 
73
+         <para>
 
74
+            No checks will be performed with regard to
 
75
+            <option>SUB_UID_MIN</option>, <option>SUB_UID_MAX</option>, or
 
76
+            <option>SUB_UID_COUNT</option> from /etc/login.defs.
 
77
+         </para>
 
78
+       </listitem>
 
79
+      </varlistentry>
 
80
+      <varlistentry>
 
81
+       <term>
 
82
+         <option>-V</option>, <option>--del-sub-uids</option>
 
83
+         <replaceable>FIRST</replaceable>-<replaceable>LAST</replaceable>
 
84
+       </term>
 
85
+       <listitem>
 
86
+         <para>
 
87
+           Remove a range of subordinate uids from the users account.
 
88
+         </para>
 
89
+         <para>
 
90
+           This option may be specified multiple times to remove multiple ranges to a users account.
 
91
+           When both <option>--del-sub-uids</option> and <option>--add-sub-uids</option> are specified
 
92
+           remove of all subordinate uid ranges happens before any subordinate uid ranges are added.
 
93
+         </para>
 
94
+         <para>
 
95
+            No checks will be performed with regard to
 
96
+            <option>SUB_UID_MIN</option>, <option>SUB_UID_MAX</option>, or
 
97
+            <option>SUB_UID_COUNT</option> from /etc/login.defs.
 
98
+         </para>
 
99
+       </listitem>
 
100
+      </varlistentry>
 
101
+      <varlistentry>
 
102
+       <term>
 
103
+         <option>-w</option>, <option>--add-sub-gids</option>
 
104
+         <replaceable>FIRST</replaceable>-<replaceable>LAST</replaceable>
 
105
+       </term>
 
106
+       <listitem>
 
107
+         <para>
 
108
+           Add a range of subordinate gids to the users account.
 
109
+         </para>
 
110
+         <para>
 
111
+           This option may be specified multiple times to add multiple ranges to a users account.
 
112
+         </para>
 
113
+         <para>
 
114
+            No checks will be performed with regard to
 
115
+            <option>SUB_GID_MIN</option>, <option>SUB_GID_MAX</option>, or
 
116
+            <option>SUB_GID_COUNT</option> from /etc/login.defs.
 
117
+         </para>
 
118
+       </listitem>
 
119
+      </varlistentry>
 
120
+      <varlistentry>
 
121
+       <term>
 
122
+         <option>-W</option>, <option>--del-sub-gids</option>
 
123
+         <replaceable>FIRST</replaceable>-<replaceable>LAST</replaceable>
 
124
+       </term>
 
125
+       <listitem>
 
126
+         <para>
 
127
+           Remove a range of subordinate gids from the users account.
 
128
+         </para>
 
129
+         <para>
 
130
+           This option may be specified multiple times to remove multiple ranges to a users account.
 
131
+           When both <option>--del-sub-gids</option> and <option>--add-sub-gids</option> are specified
 
132
+           remove of all subordinate gid ranges happens before any subordinate gid ranges are added.
 
133
+         </para>
 
134
+         <para>
 
135
+            No checks will be performed with regard to
 
136
+            <option>SUB_GID_MIN</option>, <option>SUB_GID_MAX</option>, or
 
137
+            <option>SUB_GID_COUNT</option> from /etc/login.defs.
 
138
+         </para>
 
139
+       </listitem>
 
140
+      </varlistentry>
 
141
+      <varlistentry>
 
142
+       <term>
 
143
          <option>-Z</option>, <option>--selinux-user</option>
 
144
          <replaceable>SEUSER</replaceable>
 
145
        </term>
 
146
Index: shadow/src/usermod.c
 
147
===================================================================
 
148
--- shadow.orig/src/usermod.c   2013-02-01 15:27:53.240080352 -0600
 
149
+++ shadow/src/usermod.c        2013-02-01 15:27:53.236080353 -0600
 
150
@@ -63,6 +63,7 @@
 
151
 #include "sgroupio.h"
 
152
 #endif
 
153
 #include "shadowio.h"
 
154
+#include "subordinateio.h"
 
155
 #ifdef WITH_TCB
 
156
 #include "tcbfuncs.h"
 
157
 #endif
 
158
@@ -86,6 +87,8 @@
 
159
 /* #define E_NOSPACE   11         insufficient space to move home dir */
 
160
 #define E_HOMEDIR      12      /* unable to complete home dir move */
 
161
 #define E_SE_UPDATE    13      /* can't update SELinux user mapping */
 
162
+#define E_SUB_UID_UPDATE 16    /* can't update the subordinate uid file */
 
163
+#define E_SUB_GID_UPDATE 18    /* can't update the subordinate gid file */
 
164
 #define        VALID(s)        (strcspn (s, ":\n") == strlen (s))
 
165
 /*
 
166
  * Global variables
 
167
@@ -133,7 +136,11 @@
 
168
     Zflg = false,              /* new selinux user */
 
169
 #endif
 
170
     uflg = false,              /* specify new user ID */
 
171
-    Uflg = false;              /* unlock the password */
 
172
+    Uflg = false,              /* unlock the password */
 
173
+    vflg = false,              /*    add subordinate uids */
 
174
+    Vflg = false,              /* delete subordinate uids */
 
175
+    wflg = false,              /*    add subordinate gids */
 
176
+    Wflg = false;              /* delete subordinate gids */
 
177
 
 
178
 static bool is_shadow_pwd;
 
179
 
 
180
@@ -141,12 +148,17 @@
 
181
 static bool is_shadow_grp;
 
182
 #endif
 
183
 
 
184
+static bool is_sub_uid = false;
 
185
+static bool is_sub_gid = false;
 
186
+
 
187
 static bool pw_locked  = false;
 
188
 static bool spw_locked = false;
 
189
 static bool gr_locked  = false;
 
190
 #ifdef SHADOWGRP
 
191
 static bool sgr_locked = false;
 
192
 #endif
 
193
+static bool sub_uid_locked = false;
 
194
+static bool sub_gid_locked = false;
 
195
 
 
196
 
 
197
 /* local function prototypes */
 
198
@@ -302,6 +314,69 @@
 
199
        return 0;
 
200
 }
 
201
 
 
202
+struct ulong_range
 
203
+{
 
204
+       unsigned long first;
 
205
+       unsigned long last;
 
206
+};
 
207
+
 
208
+static struct ulong_range getulong_range(const char *str)
 
209
+{
 
210
+       struct ulong_range result = { .first = ULONG_MAX, .last = 0 };
 
211
+       unsigned long long first, last;
 
212
+       char *pos;
 
213
+
 
214
+       errno = 0;
 
215
+       first = strtoll(str, &pos, 10);
 
216
+       if (('\0' == *str) || ('-' != *pos ) || (ERANGE == errno) ||
 
217
+           (first != (unsigned long int)first))
 
218
+               goto out;
 
219
+
 
220
+       errno = 0;
 
221
+       last = strtoul(pos + 1, &pos, 10);
 
222
+       if (('\0' != *pos ) || (ERANGE == errno) ||
 
223
+           (last != (unsigned long int)last))
 
224
+               goto out;
 
225
+
 
226
+       if (first > last)
 
227
+               goto out;
 
228
+
 
229
+       result.first = (unsigned long int)first;
 
230
+       result.last = (unsigned long int)last;
 
231
+out:
 
232
+       return result;
 
233
+       
 
234
+}
 
235
+
 
236
+struct ulong_range_list_entry {
 
237
+       struct ulong_range_list_entry *next;
 
238
+       struct ulong_range range;
 
239
+};
 
240
+
 
241
+static struct ulong_range_list_entry *add_sub_uids = NULL, *del_sub_uids = NULL;
 
242
+static struct ulong_range_list_entry *add_sub_gids = NULL, *del_sub_gids = NULL;
 
243
+
 
244
+static int prepend_range(const char *str, struct ulong_range_list_entry **head)
 
245
+{
 
246
+       struct ulong_range range;
 
247
+       struct ulong_range_list_entry *entry;
 
248
+       range = getulong_range(str);
 
249
+       if (range.first > range.last)
 
250
+               return 0;
 
251
+
 
252
+       entry = malloc(sizeof(*entry));
 
253
+       if (!entry) {
 
254
+               fprintf (stderr,
 
255
+                       _("%s: failed to allocate memory: %s\n"),
 
256
+                       Prog, strerror (errno));
 
257
+               return 0;
 
258
+       }
 
259
+       entry->next = *head;
 
260
+       entry->range = range;
 
261
+       *head = entry;
 
262
+       return 1;
 
263
+}
 
264
+
 
265
 /*
 
266
  * usage - display usage message and exit
 
267
  */
 
268
@@ -334,6 +409,10 @@
 
269
        (void) fputs (_("  -s, --shell SHELL             new login shell for the user account\n"), usageout);
 
270
        (void) fputs (_("  -u, --uid UID                 new UID for the user account\n"), usageout);
 
271
        (void) fputs (_("  -U, --unlock                  unlock the user account\n"), usageout);
 
272
+       (void) fputs (_("  -v, --add-subuids FIRST-LAST  add range of subordinate uids\n"), usageout);
 
273
+       (void) fputs (_("  -V, --del-subuids FIRST-LAST  remvoe range of subordinate uids\n"), usageout);
 
274
+       (void) fputs (_("  -w, --add-subgids FIRST-LAST  add range of subordinate gids\n"), usageout);
 
275
+       (void) fputs (_("  -W, --del-subgids FIRST-LAST  remvoe range of subordinate gids\n"), usageout);
 
276
 #ifdef WITH_SELINUX
 
277
        (void) fputs (_("  -Z, --selinux-user SEUSER     new SELinux user mapping for the user account\n"), usageout);
 
278
 #endif                         /* WITH_SELINUX */
 
279
@@ -590,6 +669,20 @@
 
280
                        /* continue */
 
281
                }
 
282
        }
 
283
+       if (sub_uid_locked) {
 
284
+               if (sub_uid_unlock () == 0) {
 
285
+                       fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
 
286
+                       SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
 
287
+                       /* continue */
 
288
+               }
 
289
+       }
 
290
+       if (sub_gid_locked) {
 
291
+               if (sub_gid_unlock () == 0) {
 
292
+                       fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
 
293
+                       SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
 
294
+                       /* continue */
 
295
+               }
 
296
+       }
 
297
 
 
298
 #ifdef WITH_AUDIT
 
299
        audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
 
300
@@ -889,6 +982,10 @@
 
301
                        {"shell",        required_argument, NULL, 's'},
 
302
                        {"uid",          required_argument, NULL, 'u'},
 
303
                        {"unlock",       no_argument,       NULL, 'U'},
 
304
+                       {"add-subuids",  required_argument, NULL, 'v'},
 
305
+                       {"del-subuids",  required_argument, NULL, 'V'},
 
306
+                       {"add-subgids",  required_argument, NULL, 'w'},
 
307
+                       {"del-subgids",  required_argument, NULL, 'W'},
 
308
 #ifdef WITH_SELINUX
 
309
                        {"selinux-user", required_argument, NULL, 'Z'},
 
310
 #endif                         /* WITH_SELINUX */
 
311
@@ -1018,6 +1115,41 @@
 
312
                        case 'U':
 
313
                                Uflg = true;
 
314
                                break;
 
315
+                       case 'v':
 
316
+                               if (prepend_range (optarg, &add_sub_uids) == 0) {
 
317
+                                       fprintf (stderr,
 
318
+                                               _("%s: invalid subordinate uid range '%s'\n"),
 
319
+                                               Prog, optarg);
 
320
+                                       exit(E_BAD_ARG);
 
321
+                               }
 
322
+                               vflg = true;
 
323
+                               break;
 
324
+                       case 'V':
 
325
+                               if (prepend_range (optarg, &del_sub_uids) == 0) {
 
326
+                                       fprintf (stderr,
 
327
+                                               _("%s: invalid subordinate uid range '%s'\n"),
 
328
+                                               Prog, optarg);
 
329
+                                       exit(E_BAD_ARG);
 
330
+                               }
 
331
+                               Vflg = true;
 
332
+                               break;
 
333
+                       case 'w':
 
334
+                               if (prepend_range (optarg, &add_sub_gids) == 0) {
 
335
+                                       fprintf (stderr,
 
336
+                                               _("%s: invalid subordinate gid range '%s'\n"),
 
337
+                                               Prog, optarg);
 
338
+                                       exit(E_BAD_ARG);
 
339
+                               }
 
340
+                               wflg = true;
 
341
+                       case 'W':
 
342
+                               if (prepend_range (optarg, &del_sub_gids) == 0) {
 
343
+                                       fprintf (stderr,
 
344
+                                               _("%s: invalid subordinate gid range '%s'\n"),
 
345
+                                               Prog, optarg);
 
346
+                                       exit(E_BAD_ARG);
 
347
+                               }
 
348
+                               Wflg = true;
 
349
+                               break;
 
350
 #ifdef WITH_SELINUX
 
351
                        case 'Z':
 
352
                                if (is_selinux_enabled () > 0) {
 
353
@@ -1170,6 +1302,7 @@
 
354
 
 
355
        if (!(Uflg || uflg || sflg || pflg || mflg || Lflg ||
 
356
              lflg || Gflg || gflg || fflg || eflg || dflg || cflg
 
357
+             || vflg || Vflg || wflg || Wflg
 
358
 #ifdef WITH_SELINUX
 
359
              || Zflg
 
360
 #endif                         /* WITH_SELINUX */
 
361
@@ -1200,6 +1333,7 @@
 
362
                         Prog, (unsigned long) user_newid);
 
363
                exit (E_UID_IN_USE);
 
364
        }
 
365
+
 
366
 }
 
367
 
 
368
 /*
 
369
@@ -1248,6 +1382,10 @@
 
370
                                         sgr_dbname ()));
 
371
                                fail_exit (E_GRP_UPDATE);
 
372
                        }
 
373
+               }
 
374
+#endif
 
375
+#ifdef SHADOWGRP
 
376
+               if (is_shadow_grp) {
 
377
                        if (sgr_unlock () == 0) {
 
378
                                fprintf (stderr,
 
379
                                         _("%s: failed to unlock %s\n"),
 
380
@@ -1296,6 +1434,33 @@
 
381
        sgr_locked = false;
 
382
 #endif
 
383
 
 
384
+       if (vflg || Vflg) {
 
385
+               if (!is_sub_uid || (sub_uid_close () == 0)) {
 
386
+                       fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sub_uid_dbname ());
 
387
+                       SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_uid_dbname ()));
 
388
+                       fail_exit (E_SUB_UID_UPDATE);
 
389
+               }
 
390
+               if (!is_sub_uid || (sub_uid_unlock () == 0)) {
 
391
+                       fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
 
392
+                       SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
 
393
+                       /* continue */
 
394
+               }
 
395
+               sub_uid_locked = false;
 
396
+       }
 
397
+       if (wflg || Wflg) {
 
398
+               if (!is_sub_gid || (sub_gid_close () == 0)) {
 
399
+                       fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sub_gid_dbname ());
 
400
+                       SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_gid_dbname ()));
 
401
+                       fail_exit (E_SUB_GID_UPDATE);
 
402
+               }
 
403
+               if (!is_sub_gid || (sub_gid_unlock () == 0)) {
 
404
+                       fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
 
405
+                       SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
 
406
+                       /* continue */
 
407
+               }
 
408
+               sub_gid_locked = false;
 
409
+       }
 
410
+
 
411
        /*
 
412
         * Close the DBM and/or flat files
 
413
         */
 
414
@@ -1375,6 +1540,36 @@
 
415
                }
 
416
 #endif
 
417
        }
 
418
+       if (vflg || Vflg) {
 
419
+               if (!is_sub_uid || (sub_uid_lock () == 0)) {
 
420
+                       fprintf (stderr,
 
421
+                                _("%s: cannot lock %s; try again later.\n"),
 
422
+                                Prog, sub_uid_dbname ());
 
423
+                       fail_exit (E_SUB_UID_UPDATE);
 
424
+               }
 
425
+               sub_uid_locked = true;
 
426
+               if (!is_sub_uid || (sub_uid_open (O_RDWR) == 0)) {
 
427
+                       fprintf (stderr,
 
428
+                                _("%s: cannot open %s\n"),
 
429
+                                Prog, sub_uid_dbname ());
 
430
+                       fail_exit (E_SUB_UID_UPDATE);
 
431
+               }
 
432
+       }
 
433
+       if (wflg || Wflg) {
 
434
+               if (!is_sub_gid || (sub_gid_lock () == 0)) {
 
435
+                       fprintf (stderr,
 
436
+                                _("%s: cannot lock %s; try again later.\n"),
 
437
+                                Prog, sub_gid_dbname ());
 
438
+                       fail_exit (E_SUB_GID_UPDATE);
 
439
+               }
 
440
+               sub_gid_locked = true;
 
441
+               if (!is_sub_gid || (sub_gid_open (O_RDWR) == 0)) {
 
442
+                       fprintf (stderr,
 
443
+                                _("%s: cannot open %s\n"),
 
444
+                                Prog, sub_gid_dbname ());
 
445
+                       fail_exit (E_SUB_GID_UPDATE);
 
446
+               }
 
447
+       }
 
448
 }
 
449
 
 
450
 /*
 
451
@@ -1476,6 +1671,58 @@
 
452
                        fail_exit (E_PW_UPDATE);
 
453
                }
 
454
        }
 
455
+       if (Vflg) {
 
456
+               struct ulong_range_list_entry *ptr;
 
457
+               for (ptr = del_sub_uids; ptr != NULL; ptr = ptr->next) {
 
458
+                       unsigned long count = ptr->range.last - ptr->range.first + 1;
 
459
+                       if (sub_uid_remove(user_name, ptr->range.first, count) == 0) {
 
460
+                               fprintf (stderr,
 
461
+                                       _("%s: failed to remove uid range %lu-%lu from '%s'\n"),
 
462
+                                       Prog, ptr->range.first, ptr->range.last, 
 
463
+                                       sub_uid_dbname ());
 
464
+                               fail_exit (E_SUB_UID_UPDATE);
 
465
+                       }
 
466
+               }
 
467
+       }
 
468
+       if (vflg) {
 
469
+               struct ulong_range_list_entry *ptr;
 
470
+               for (ptr = add_sub_uids; ptr != NULL; ptr = ptr->next) {
 
471
+                       unsigned long count = ptr->range.last - ptr->range.first + 1;
 
472
+                       if (sub_uid_add(user_name, ptr->range.first, count) == 0) {
 
473
+                               fprintf (stderr,
 
474
+                                       _("%s: failed to add uid range %lu-%lu from '%s'\n"),
 
475
+                                       Prog, ptr->range.first, ptr->range.last, 
 
476
+                                       sub_uid_dbname ());
 
477
+                               fail_exit (E_SUB_UID_UPDATE);
 
478
+                       }
 
479
+               }
 
480
+       }
 
481
+       if (Wflg) {
 
482
+               struct ulong_range_list_entry *ptr;
 
483
+               for (ptr = del_sub_gids; ptr != NULL; ptr = ptr->next) {
 
484
+                       unsigned long count = ptr->range.last - ptr->range.first + 1;
 
485
+                       if (sub_gid_remove(user_name, ptr->range.first, count) == 0) {
 
486
+                               fprintf (stderr,
 
487
+                                       _("%s: failed to remove gid range %lu-%lu from '%s'\n"),
 
488
+                                       Prog, ptr->range.first, ptr->range.last, 
 
489
+                                       sub_gid_dbname ());
 
490
+                               fail_exit (E_SUB_GID_UPDATE);
 
491
+                       }
 
492
+               }
 
493
+       }
 
494
+       if (wflg) {
 
495
+               struct ulong_range_list_entry *ptr;
 
496
+               for (ptr = add_sub_gids; ptr != NULL; ptr = ptr->next) {
 
497
+                       unsigned long count = ptr->range.last - ptr->range.first + 1;
 
498
+                       if (sub_gid_add(user_name, ptr->range.first, count) == 0) {
 
499
+                               fprintf (stderr,
 
500
+                                       _("%s: failed to add gid range %lu-%lu from '%s'\n"),
 
501
+                                       Prog, ptr->range.first, ptr->range.last, 
 
502
+                                       sub_gid_dbname ());
 
503
+                               fail_exit (E_SUB_GID_UPDATE);
 
504
+                       }
 
505
+               }
 
506
+       }
 
507
 }
 
508
 
 
509
 /*
 
510
@@ -1811,6 +2058,8 @@
 
511
 #ifdef SHADOWGRP
 
512
        is_shadow_grp = sgr_file_present ();
 
513
 #endif
 
514
+       is_sub_uid = sub_uid_file_present ();
 
515
+       is_sub_gid = sub_gid_file_present ();
 
516
 
 
517
        process_flags (argc, argv);
 
518
 
 
519
@@ -1818,7 +2067,7 @@
 
520
         * The home directory, the username and the user's UID should not
 
521
         * be changed while the user is logged in.
 
522
         */
 
523
-       if (   (uflg || lflg || dflg)
 
524
+       if (   (uflg || lflg || dflg || Vflg || Wflg)
 
525
            && (user_busy (user_name, user_id) != 0)) {
 
526
                exit (E_USER_BUSY);
 
527
        }
 
528
@@ -1871,7 +2120,7 @@
 
529
         */
 
530
        open_files ();
 
531
        if (   cflg || dflg || eflg || fflg || gflg || Lflg || lflg || pflg
 
532
-           || sflg || uflg || Uflg) {
 
533
+           || sflg || uflg || Uflg || vflg || Vflg || wflg || Wflg) {
 
534
                usr_update ();
 
535
        }
 
536
        if (Gflg || lflg) {