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

« back to all changes in this revision

Viewing changes to debian/patches/userns/04_userns_add_backend_support

  • 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:16:29 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 AF9A9C80F4; Tue, 22 Jan 2013 09:16:29 +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 EDF70C80D1
 
15
        for <serge@hallyn.com>; Tue, 22 Jan 2013 09:16:24 +0000 (UTC)
 
16
Received: from out01.mta.xmission.com ([166.70.13.231])
 
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 1TxZwI-0007HS-Mn; Tue, 22 Jan 2013 02:14:42 -0700
 
21
Received: from in02.mta.xmission.com ([166.70.13.52])
 
22
        by out01.mta.xmission.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
 
23
        (Exim 4.76)
 
24
        (envelope-from <ebiederm@xmission.com>)
 
25
        id 1TxZwI-0005wP-8E; Tue, 22 Jan 2013 02:14:42 -0700
 
26
Received: from c-98-207-153-68.hsd1.ca.comcast.net ([98.207.153.68] helo=eric-ThinkPad-X220.xmission.com)
 
27
        by in02.mta.xmission.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16)
 
28
        (Exim 4.76)
 
29
        (envelope-from <ebiederm@xmission.com>)
 
30
        id 1TxZwE-0004bA-Mv; Tue, 22 Jan 2013 02:14:42 -0700
 
31
From: ebiederm@xmission.com (Eric W. Biederman)
 
32
To: Nicolas =?utf-8?Q?Fran=C3=A7ois?= <nicolas.francois@centraliens.net>
 
33
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>
 
34
References: <87d2wxshu0.fsf@xmission.com>
 
35
Date: Tue, 22 Jan 2013 01:14:35 -0800
 
36
In-Reply-To: <87d2wxshu0.fsf@xmission.com> (Eric W. Biederman's message of
 
37
        "Tue, 22 Jan 2013 01:11:19 -0800")
 
38
Message-ID: <87liblr344.fsf@xmission.com>
 
39
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)
 
40
MIME-Version: 1.0
 
41
Content-Type: text/plain
 
42
X-XM-AID: U2FsdGVkX1/3QOlmT6VsAuzQbs/RJ/nb1IrpO++QYVA=
 
43
X-SA-Exim-Connect-IP: 98.207.153.68
 
44
X-SA-Exim-Mail-From: ebiederm@xmission.com
 
45
Subject: [PATCH 04/11] Add backend support for suboridnate uids and gids
 
46
X-SA-Exim-Version: 4.2.1 (built Wed, 14 Nov 2012 14:26:46 -0700)
 
47
X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com)
 
48
X-UID: 2074                                                  
 
49
Status: RO
 
50
X-Status: A
 
51
Content-Length: 15967
 
52
Lines: 636
 
53
 
 
54
 
 
55
These files list the set of subordinate uids and gids that users are allowed
 
56
to use.   The expect use case is with the user namespace but other uses are
 
57
allowed.
 
58
 
 
59
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
 
60
---
 
61
 etc/login.defs      |    8 +
 
62
 lib/Makefile.am     |    2 +
 
63
 lib/getdef.c        |    6 +
 
64
 lib/subordinateio.c |  512 +++++++++++++++++++++++++++++++++++++++++++++++++++
 
65
 lib/subordinateio.h |   38 ++++
 
66
 5 files changed, 566 insertions(+), 0 deletions(-)
 
67
 create mode 100644 lib/subordinateio.c
 
68
 create mode 100644 lib/subordinateio.h
 
69
 
 
70
Index: shadow/etc/login.defs
 
71
===================================================================
 
72
--- shadow.orig/etc/login.defs  2013-02-01 15:27:51.684080379 -0600
 
73
+++ shadow/etc/login.defs       2013-02-01 15:27:51.676080379 -0600
 
74
@@ -226,6 +226,10 @@
 
75
 # System accounts
 
76
 SYS_UID_MIN              101
 
77
 SYS_UID_MAX              999
 
78
+# Extra per user uids
 
79
+SUB_UID_MIN               100000
 
80
+SUB_UID_MAX            600100000
 
81
+SUB_UID_COUNT              10000
 
82
 
 
83
 #
 
84
 # Min/max values for automatic gid selection in groupadd
 
85
@@ -235,6 +239,10 @@
 
86
 # System accounts
 
87
 SYS_GID_MIN              101
 
88
 SYS_GID_MAX              999
 
89
+# Extra per user group ids
 
90
+SUB_GID_MIN               100000
 
91
+SUB_GID_MAX            600100000
 
92
+SUB_GID_COUNT              10000
 
93
 
 
94
 #
 
95
 # Max number of login retries if password is bad
 
96
Index: shadow/lib/Makefile.am
 
97
===================================================================
 
98
--- shadow.orig/lib/Makefile.am 2013-02-01 15:27:51.684080379 -0600
 
99
+++ shadow/lib/Makefile.am      2013-02-01 15:27:51.676080379 -0600
 
100
@@ -39,6 +39,8 @@
 
101
        pwio.c \
 
102
        pwio.h \
 
103
        pwmem.c \
 
104
+       subordinateio.h \
 
105
+       subordinateio.c \
 
106
        selinux.c \
 
107
        semanage.c \
 
108
        sgetgrent.c \
 
109
Index: shadow/lib/getdef.c
 
110
===================================================================
 
111
--- shadow.orig/lib/getdef.c    2013-02-01 15:27:51.684080379 -0600
 
112
+++ shadow/lib/getdef.c 2013-02-01 15:27:51.680080379 -0600
 
113
@@ -82,6 +82,12 @@
 
114
        {"SHA_CRYPT_MAX_ROUNDS", NULL},
 
115
        {"SHA_CRYPT_MIN_ROUNDS", NULL},
 
116
 #endif
 
117
+       {"SUB_GID_COUNT", NULL},
 
118
+       {"SUB_GID_MAX", NULL},
 
119
+       {"SUB_GID_MIN", NULL},
 
120
+       {"SUB_UID_COUNT", NULL},
 
121
+       {"SUB_UID_MAX", NULL},
 
122
+       {"SUB_UID_MIN", NULL},
 
123
        {"SULOG_FILE", NULL},
 
124
        {"SU_NAME", NULL},
 
125
        {"SYS_GID_MAX", NULL},
 
126
Index: shadow/lib/subordinateio.c
 
127
===================================================================
 
128
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
 
129
+++ shadow/lib/subordinateio.c  2013-02-01 15:27:51.680080379 -0600
 
130
@@ -0,0 +1,512 @@
 
131
+/*
 
132
+ * Copyright (c) 2012 - Eric Biederman
 
133
+ */
 
134
+
 
135
+#include <config.h>
 
136
+#include "prototypes.h"
 
137
+#include "defines.h"
 
138
+#include <stdio.h>
 
139
+#include "commonio.h"
 
140
+#include "subordinateio.h"
 
141
+
 
142
+struct subordinate_range {
 
143
+       const char *owner;
 
144
+       unsigned long start;
 
145
+       unsigned long count;
 
146
+};
 
147
+
 
148
+#define NFIELDS 3
 
149
+
 
150
+static /*@null@*/ /*@only@*/void *subordinate_dup (const void *ent)
 
151
+{
 
152
+       const struct subordinate_range *rangeent = ent;
 
153
+       struct subordinate_range *range;
 
154
+
 
155
+       range = (struct subordinate_range *) malloc (sizeof *range);
 
156
+       if (NULL == range) {
 
157
+               return NULL;
 
158
+       }
 
159
+       range->owner = strdup (rangeent->owner);
 
160
+       if (NULL == range->owner) {
 
161
+               free(range);
 
162
+               return NULL;
 
163
+       }
 
164
+       range->start = rangeent->start;
 
165
+       range->count = rangeent->count;
 
166
+
 
167
+       return range;
 
168
+}
 
169
+
 
170
+static void subordinate_free (/*@out@*/ /*@only@*/void *ent)
 
171
+{
 
172
+       struct subordinate_range *rangeent = ent;
 
173
+       
 
174
+       free ((void *)(rangeent->owner));
 
175
+       free (rangeent);
 
176
+}
 
177
+
 
178
+static void *subordinate_parse (const char *line)
 
179
+{
 
180
+       static struct subordinate_range range;
 
181
+       char rangebuf[1024];
 
182
+       int i;
 
183
+       char *cp;
 
184
+       char *fields[NFIELDS];
 
185
+
 
186
+       /*
 
187
+        * Copy the string to a temporary buffer so the substrings can
 
188
+        * be modified to be NULL terminated.
 
189
+        */
 
190
+       if (strlen (line) >= sizeof rangebuf)
 
191
+               return NULL;    /* fail if too long */
 
192
+       strcpy (rangebuf, line);
 
193
+
 
194
+       /*
 
195
+        * Save a pointer to the start of each colon separated
 
196
+        * field.  The fields are converted into NUL terminated strings.
 
197
+        */
 
198
+
 
199
+       for (cp = rangebuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) {
 
200
+               fields[i] = cp;
 
201
+               while (('\0' != *cp) && (':' != *cp)) {
 
202
+                       cp++;
 
203
+               }
 
204
+
 
205
+               if ('\0' != *cp) {
 
206
+                       *cp = '\0';
 
207
+                       cp++;
 
208
+               } else {
 
209
+                       cp = NULL;
 
210
+               }
 
211
+       }
 
212
+
 
213
+       /*
 
214
+        * There must be exactly NFIELDS colon separated fields or
 
215
+        * the entry is invalid.  Also, fields must be non-blank.
 
216
+        */
 
217
+       if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
 
218
+               return NULL;
 
219
+       range.owner = fields[0];
 
220
+       if (getulong (fields[1], &range.start) == 0)
 
221
+               return NULL;
 
222
+       if (getulong (fields[2], &range.count) == 0)
 
223
+               return NULL;
 
224
+
 
225
+       return &range;
 
226
+}
 
227
+
 
228
+static int subordinate_put (const void *ent, FILE * file)
 
229
+{
 
230
+       const struct subordinate_range *range = ent;
 
231
+
 
232
+       return fprintf(file, "%s:%lu:%lu\n",
 
233
+                              range->owner,
 
234
+                              range->start,
 
235
+                              range->count) < 0 ? -1  : 0;
 
236
+}
 
237
+
 
238
+static struct commonio_ops subordinate_ops = {
 
239
+       subordinate_dup,        /* dup */
 
240
+       subordinate_free,       /* free */
 
241
+       NULL,                   /* getname */
 
242
+       subordinate_parse,      /* parse */
 
243
+       subordinate_put,        /* put */
 
244
+       fgets,                  /* fgets */
 
245
+       fputs,                  /* fputs */
 
246
+       NULL,                   /* open_hook */
 
247
+       NULL,                   /* close_hook */
 
248
+};
 
249
+
 
250
+static /*@observer@*/ /*@null*/const struct subordinate_range *subordinate_next(struct commonio_db *db)
 
251
+{
 
252
+       commonio_next (db);
 
253
+}
 
254
+
 
255
+static bool is_range_free(struct commonio_db *db, unsigned long start,
 
256
+                         unsigned long count)
 
257
+{
 
258
+       const struct subordinate_range *range;
 
259
+       unsigned long end = start + count - 1;
 
260
+
 
261
+       commonio_rewind(db);
 
262
+       while ((range = commonio_next(db)) != NULL) {
 
263
+               unsigned long first = range->start;
 
264
+               unsigned long last = first + range->count - 1;
 
265
+
 
266
+               if ((end >= first) && (start <= last))
 
267
+                       return false;
 
268
+       }
 
269
+       return true;
 
270
+}
 
271
+
 
272
+static const bool range_exists(struct commonio_db *db, const char *owner)
 
273
+{
 
274
+       const struct subordinate_range *range;
 
275
+       commonio_rewind(db);
 
276
+       while ((range = commonio_next(db)) != NULL) {
 
277
+               unsigned long first = range->start;
 
278
+               unsigned long last = first + range->count - 1;
 
279
+
 
280
+               if (0 == strcmp(range->owner, owner))
 
281
+                       return true;
 
282
+       }
 
283
+       return false;
 
284
+}
 
285
+
 
286
+static const struct subordinate_range *find_range(struct commonio_db *db,
 
287
+                                                 const char *owner, unsigned long val)
 
288
+{
 
289
+       const struct subordinate_range *range;
 
290
+       commonio_rewind(db);
 
291
+       while ((range = commonio_next(db)) != NULL) {
 
292
+               unsigned long first = range->start;
 
293
+               unsigned long last = first + range->count - 1;
 
294
+
 
295
+               if (0 != strcmp(range->owner, owner))
 
296
+                       continue;
 
297
+
 
298
+               if ((val >= first) && (val <= last))
 
299
+                       return range;
 
300
+       }
 
301
+       return NULL;
 
302
+}
 
303
+
 
304
+static bool have_range(struct commonio_db *db,
 
305
+                      const char *owner, unsigned long start, unsigned long count)
 
306
+{
 
307
+       const struct subordinate_range *range;
 
308
+       unsigned long end;
 
309
+
 
310
+       if (count == 0)
 
311
+               return false;
 
312
+
 
313
+       end = start + count - 1;
 
314
+       range = find_range (db, owner, start);
 
315
+       while (range) {
 
316
+               unsigned long last; 
 
317
+
 
318
+               last = range->start + range->count - 1;
 
319
+               if (last >= (start + count - 1))
 
320
+                       return true;
 
321
+
 
322
+               count = end - last;
 
323
+               start = last + 1;
 
324
+               range = find_range(db, owner, start);
 
325
+       }
 
326
+       return false;
 
327
+}
 
328
+
 
329
+static int subordinate_range_cmp (const void *p1, const void *p2)
 
330
+{
 
331
+       struct subordinate_range *range1, *range2;
 
332
+
 
333
+       if ((*(struct commonio_entry **) p1)->eptr == NULL)
 
334
+               return 1;
 
335
+       if ((*(struct commonio_entry **) p2)->eptr == NULL)
 
336
+               return -1;
 
337
+
 
338
+       range1 = ((struct subordinate_range *) (*(struct commonio_entry **) p1)->eptr);
 
339
+       range2 = ((struct subordinate_range *) (*(struct commonio_entry **) p2)->eptr);
 
340
+
 
341
+       if (range1->start < range2->start)
 
342
+               return -1;
 
343
+       else if (range1->start > range2->start)
 
344
+               return 1;
 
345
+       else if (range1->count < range2->count)
 
346
+               return -1;
 
347
+       else if (range1->count > range2->count)
 
348
+               return 1;
 
349
+       else
 
350
+               return strcmp(range1->owner, range2->owner);
 
351
+}
 
352
+
 
353
+static unsigned long find_free_range(struct commonio_db *db,
 
354
+                                    unsigned long min, unsigned long max,
 
355
+                                    unsigned long count)
 
356
+{
 
357
+       const struct subordinate_range *range;
 
358
+       unsigned long low, high;
 
359
+
 
360
+       /* When given invalid parameters fail */
 
361
+       if ((count == 0) || (max <= min))
 
362
+               goto fail;
 
363
+
 
364
+       /* Sort by range than by owner */
 
365
+       commonio_sort (db, subordinate_range_cmp);
 
366
+       commonio_rewind(db);
 
367
+
 
368
+       low = min;
 
369
+       while ((range = commonio_next(db)) != NULL) {
 
370
+               unsigned long first = range->start;
 
371
+               unsigned long last = first + range->count - 1;
 
372
+
 
373
+               /* Find the top end of the hole before this range */
 
374
+               high = first;
 
375
+               if (high > max)
 
376
+                       high = max;
 
377
+
 
378
+               /* Is the hole before this range large enough? */
 
379
+               if ((high > low) && (((high - low) + 1) >= count))
 
380
+                       return low;
 
381
+
 
382
+               /* Compute the low end of the next hole */
 
383
+               if (low < (last + 1))
 
384
+                       low = last + 1;
 
385
+               if (low > max)
 
386
+                       goto fail;
 
387
+       }
 
388
+
 
389
+       /* Is the remaining unclaimed area large enough? */
 
390
+       if (((max - low) + 1) >= count)
 
391
+               return low;
 
392
+fail:
 
393
+       return ULONG_MAX;
 
394
+}
 
395
+
 
396
+static int add_range(struct commonio_db *db,
 
397
+       const char *owner, unsigned long start, unsigned long count)
 
398
+{
 
399
+       struct subordinate_range range;
 
400
+       range.owner = owner;
 
401
+       range.start = start;
 
402
+       range.count = count;
 
403
+
 
404
+       /* See if the range is already present */
 
405
+       if (have_range(db, owner, start, count))
 
406
+               return 1;
 
407
+
 
408
+       /* Oterwise append the range */
 
409
+       return commonio_append(db, &range);
 
410
+}
 
411
+
 
412
+static int remove_range(struct commonio_db *db,
 
413
+       const char *owner, unsigned long start, unsigned long count)
 
414
+{
 
415
+       struct commonio_entry *ent;
 
416
+       unsigned long end;
 
417
+
 
418
+       if (count == 0)
 
419
+               return 1;
 
420
+
 
421
+       end = start + count - 1;
 
422
+       for (ent = db->head; ent; ent = ent->next) {
 
423
+               struct subordinate_range *range = ent->eptr;
 
424
+               unsigned long first;
 
425
+               unsigned long last;
 
426
+
 
427
+               /* Skip unparsed entries */
 
428
+               if (!range)
 
429
+                       continue;
 
430
+
 
431
+               first = range->start;
 
432
+               last = first + range->count - 1;
 
433
+
 
434
+               /* Skip entries with a different owner */
 
435
+               if (0 != strcmp(range->owner, owner))
 
436
+                       continue;
 
437
+
 
438
+               /* Skip entries outside of the range to remove */
 
439
+               if ((end < first) || (start > last))
 
440
+                       continue;
 
441
+
 
442
+               /* Is entry completely contained in the range to remove? */
 
443
+               if ((start <= first) && (end >= last)) {
 
444
+                       commonio_del_entry (db, ent);
 
445
+               } 
 
446
+               /* Is just the start of the entry removed? */
 
447
+               else if ((start <= first) && (end < last)) {
 
448
+                       range->start = end + 1;
 
449
+                       range->count = (last - range->start) + 1;
 
450
+
 
451
+                       ent->changed = true;
 
452
+               }
 
453
+               /* Is just the end of the entry removed? */
 
454
+               else if ((start > first) && (end >= last)) {
 
455
+                       range->count = (start - range->start) + 1;
 
456
+
 
457
+                       ent->changed = true;
 
458
+               }
 
459
+               /* The middle of the range is removed */
 
460
+               else {
 
461
+                       struct subordinate_range tail;
 
462
+                       tail.owner = range->owner;
 
463
+                       tail.start = end + 1;
 
464
+                       tail.count = (last - tail.start) + 1;
 
465
+
 
466
+                       if (!commonio_append(db, &tail))
 
467
+                               return 0;
 
468
+
 
469
+                       range->count = (start - range->start) + 1;
 
470
+
 
471
+                       ent->changed = true;
 
472
+               }
 
473
+       }
 
474
+
 
475
+       return 1;
 
476
+}
 
477
+
 
478
+static struct commonio_db subordinate_uid_db = {
 
479
+       "/etc/subuid",          /* filename */
 
480
+       &subordinate_ops,       /* ops */
 
481
+       NULL,                   /* fp */
 
482
+#ifdef WITH_SELINUX
 
483
+       NULL,                   /* scontext */
 
484
+#endif
 
485
+       NULL,                   /* head */
 
486
+       NULL,                   /* tail */
 
487
+       NULL,                   /* cursor */
 
488
+       false,                  /* changed */
 
489
+       false,                  /* isopen */
 
490
+       false,                  /* locked */
 
491
+       false                   /* readonly */
 
492
+};
 
493
+
 
494
+int sub_uid_setdbname (const char *filename)
 
495
+{
 
496
+       return commonio_setname (&subordinate_uid_db, filename);
 
497
+}
 
498
+
 
499
+/*@observer@*/const char *sub_uid_dbname (void)
 
500
+{
 
501
+       return subordinate_uid_db.filename;
 
502
+}
 
503
+
 
504
+bool sub_uid_file_present (void)
 
505
+{
 
506
+       return commonio_present (&subordinate_uid_db);
 
507
+}
 
508
+
 
509
+int sub_uid_lock (void)
 
510
+{
 
511
+       return commonio_lock (&subordinate_uid_db);
 
512
+}
 
513
+
 
514
+int sub_uid_open (int mode)
 
515
+{
 
516
+       return commonio_open (&subordinate_uid_db, mode);
 
517
+}
 
518
+
 
519
+bool is_sub_uid_range_free(uid_t start, unsigned long count)
 
520
+{
 
521
+       return is_range_free (&subordinate_uid_db, start, count);
 
522
+}
 
523
+
 
524
+bool sub_uid_assigned(const char *owner)
 
525
+{
 
526
+       return range_exists (&subordinate_uid_db, owner);
 
527
+}
 
528
+
 
529
+bool have_sub_uids(const char *owner, uid_t start, unsigned long count)
 
530
+{
 
531
+       return have_range (&subordinate_uid_db, owner, start, count);
 
532
+}
 
533
+
 
534
+int sub_uid_add (const char *owner, uid_t start, unsigned long count)
 
535
+{
 
536
+       return add_range (&subordinate_uid_db, owner, start, count);
 
537
+}
 
538
+
 
539
+int sub_uid_remove (const char *owner, uid_t start, unsigned long count)
 
540
+{
 
541
+       return remove_range (&subordinate_uid_db, owner, start, count);
 
542
+}
 
543
+
 
544
+int sub_uid_close (void)
 
545
+{
 
546
+       return commonio_close (&subordinate_uid_db);
 
547
+}
 
548
+
 
549
+int sub_uid_unlock (void)
 
550
+{
 
551
+       return commonio_unlock (&subordinate_uid_db);
 
552
+}
 
553
+
 
554
+uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count)
 
555
+{
 
556
+       unsigned long start;
 
557
+       start = find_free_range (&subordinate_uid_db, min, max, count);
 
558
+       return start == ULONG_MAX ? (uid_t) -1 : start;
 
559
+}
 
560
+
 
561
+static struct commonio_db subordinate_gid_db = {
 
562
+       "/etc/subgid",          /* filename */
 
563
+       &subordinate_ops,       /* ops */
 
564
+       NULL,                   /* fp */
 
565
+#ifdef WITH_SELINUX
 
566
+       NULL,                   /* scontext */
 
567
+#endif
 
568
+       NULL,                   /* head */
 
569
+       NULL,                   /* tail */
 
570
+       NULL,                   /* cursor */
 
571
+       false,                  /* changed */
 
572
+       false,                  /* isopen */
 
573
+       false,                  /* locked */
 
574
+       false                   /* readonly */
 
575
+};
 
576
+
 
577
+int sub_gid_setdbname (const char *filename)
 
578
+{
 
579
+       return commonio_setname (&subordinate_gid_db, filename);
 
580
+}
 
581
+
 
582
+/*@observer@*/const char *sub_gid_dbname (void)
 
583
+{
 
584
+       return subordinate_gid_db.filename;
 
585
+}
 
586
+
 
587
+bool sub_gid_file_present (void)
 
588
+{
 
589
+       return commonio_present (&subordinate_gid_db);
 
590
+}
 
591
+
 
592
+int sub_gid_lock (void)
 
593
+{
 
594
+       return commonio_lock (&subordinate_gid_db);
 
595
+}
 
596
+
 
597
+int sub_gid_open (int mode)
 
598
+{
 
599
+       return commonio_open (&subordinate_gid_db, mode);
 
600
+}
 
601
+
 
602
+bool is_sub_gid_range_free(gid_t start, unsigned long count)
 
603
+{
 
604
+       return is_range_free (&subordinate_gid_db, start, count);
 
605
+}
 
606
+
 
607
+bool have_sub_gids(const char *owner, gid_t start, unsigned long count)
 
608
+{
 
609
+       return have_range(&subordinate_gid_db, owner, start, count);
 
610
+}
 
611
+
 
612
+bool sub_gid_assigned(const char *owner)
 
613
+{
 
614
+       return range_exists (&subordinate_gid_db, owner);
 
615
+}
 
616
+
 
617
+int sub_gid_add (const char *owner, gid_t start, unsigned long count)
 
618
+{
 
619
+       return add_range (&subordinate_gid_db, owner, start, count);
 
620
+}
 
621
+
 
622
+int sub_gid_remove (const char *owner, gid_t start, unsigned long count)
 
623
+{
 
624
+       return remove_range (&subordinate_gid_db, owner, start, count);
 
625
+}
 
626
+
 
627
+int sub_gid_close (void)
 
628
+{
 
629
+       return commonio_close (&subordinate_gid_db);
 
630
+}
 
631
+
 
632
+int sub_gid_unlock (void)
 
633
+{
 
634
+       return commonio_unlock (&subordinate_gid_db);
 
635
+}
 
636
+
 
637
+gid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count)
 
638
+{
 
639
+       unsigned long start;
 
640
+       start = find_free_range (&subordinate_gid_db, min, max, count);
 
641
+       return start == ULONG_MAX ? (gid_t) -1 : start;
 
642
+}
 
643
Index: shadow/lib/subordinateio.h
 
644
===================================================================
 
645
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
 
646
+++ shadow/lib/subordinateio.h  2013-02-01 15:27:51.680080379 -0600
 
647
@@ -0,0 +1,38 @@
 
648
+/*
 
649
+ * Copyright (c) 2012- Eric W. Biederman
 
650
+ */
 
651
+
 
652
+#ifndef _SUBORDINATEIO_H
 
653
+#define _SUBORDINATEIO_H
 
654
+
 
655
+#include <sys/types.h>
 
656
+
 
657
+extern int sub_uid_close(void);
 
658
+extern bool is_sub_uid_range_free(uid_t start, unsigned long count);
 
659
+extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count);
 
660
+extern bool sub_uid_file_present (void);
 
661
+extern bool sub_uid_assigned(const char *owner);
 
662
+extern int sub_uid_lock (void);
 
663
+extern int sub_uid_setdbname (const char *filename);
 
664
+extern /*@observer@*/const char *sub_uid_dbname (void);
 
665
+extern int sub_uid_open (int mode);
 
666
+extern int sub_uid_unlock (void);
 
667
+extern int sub_uid_add (const char *owner, uid_t start, unsigned long count);
 
668
+extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count);
 
669
+extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count);
 
670
+
 
671
+extern int sub_gid_close(void);
 
672
+extern bool is_sub_gid_range_free(gid_t start, unsigned long count);
 
673
+extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count);
 
674
+extern bool sub_gid_file_present (void);
 
675
+extern bool sub_gid_assigned(const char *owner);
 
676
+extern int sub_gid_lock (void);
 
677
+extern int sub_gid_setdbname (const char *filename);
 
678
+extern /*@observer@*/const char *sub_gid_dbname (void);
 
679
+extern int sub_gid_open (int mode);
 
680
+extern int sub_gid_unlock (void);
 
681
+extern int sub_gid_add (const char *owner, gid_t start, unsigned long count);
 
682
+extern int sub_gid_remove (const char *owner, gid_t start, unsigned long count);
 
683
+extern uid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count);
 
684
+
 
685
+#endif