2 * Copyright (c) 1990 - 1994, Julianne Frances Haugh
3 * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4 * Copyright (c) 2001 , Michał Moskal
5 * Copyright (c) 2005 , Tomasz Kłoczko
6 * Copyright (c) 2007 - 2009, Nicolas François
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the copyright holders or contributors may not be used to
18 * endorse or promote products derived from this software without
19 * specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #ident "$Id: groupio.c 2822 2009-04-27 20:18:00Z nekral-guest $"
41 #include "prototypes.h"
47 static /*@null@*/struct commonio_entry *merge_group_entries (
48 /*@null@*/ /*@returned@*/struct commonio_entry *gr1,
49 /*@null@*/struct commonio_entry *gr2);
50 static int split_groups (unsigned int max_members);
51 static int group_open_hook (void);
53 static /*@null@*/ /*@only@*/void *group_dup (const void *ent)
55 const struct group *gr = ent;
60 static void group_free (/*@out@*/ /*@only@*/void *ent)
62 struct group *gr = ent;
67 static const char *group_getname (const void *ent)
69 const struct group *gr = ent;
74 static void *group_parse (const char *line)
76 return (void *) sgetgrent (line);
79 static int group_put (const void *ent, FILE * file)
81 const struct group *gr = ent;
83 return (putgrent (gr, file) == -1) ? -1 : 0;
86 static int group_close_hook (void)
88 unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
90 if (0 == max_members) {
94 return split_groups (max_members);
97 static struct commonio_ops group_ops = {
109 static /*@owned@*/struct commonio_db group_db = {
110 GROUP_FILE, /* filename */
111 &group_ops, /* ops */
125 int gr_setdbname (const char *filename)
127 return commonio_setname (&group_db, filename);
130 /*@observer@*/const char *gr_dbname (void)
132 return group_db.filename;
137 return commonio_lock (&group_db);
140 int gr_open (int mode)
142 return commonio_open (&group_db, mode);
145 /*@observer@*/ /*@null@*/const struct group *gr_locate (const char *name)
147 return commonio_locate (&group_db, name);
150 /*@observer@*/ /*@null@*/const struct group *gr_locate_gid (gid_t gid)
152 const struct group *grp;
155 while ( ((grp = gr_next ()) != NULL)
156 && (grp->gr_gid != gid)) {
162 int gr_update (const struct group *gr)
164 return commonio_update (&group_db, (const void *) gr);
167 int gr_remove (const char *name)
169 return commonio_remove (&group_db, name);
174 return commonio_rewind (&group_db);
177 /*@observer@*/ /*@null@*/const struct group *gr_next (void)
179 return commonio_next (&group_db);
184 return commonio_close (&group_db);
189 return commonio_unlock (&group_db);
192 void __gr_set_changed (void)
194 group_db.changed = true;
197 /*@dependent@*/ /*@null@*/struct commonio_entry *__gr_get_head (void)
199 return group_db.head;
202 /*@observer@*/const struct commonio_db *__gr_get_db (void)
207 void __gr_del_entry (const struct commonio_entry *ent)
209 commonio_del_entry (&group_db, ent);
212 static int gr_cmp (const void *p1, const void *p2)
216 if ((*(struct commonio_entry **) p1)->eptr == NULL) {
219 if ((*(struct commonio_entry **) p2)->eptr == NULL) {
223 u1 = ((struct group *) (*(struct commonio_entry **) p1)->eptr)->gr_gid;
224 u2 = ((struct group *) (*(struct commonio_entry **) p2)->eptr)->gr_gid;
228 } else if (u1 > u2) {
235 /* Sort entries by GID */
238 return commonio_sort (&group_db, gr_cmp);
241 static int group_open_hook (void)
243 unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
244 struct commonio_entry *gr1, *gr2;
246 if (0 == max_members) {
250 for (gr1 = group_db.head; NULL != gr1; gr1 = gr1->next) {
251 for (gr2 = gr1->next; NULL != gr2; gr2 = gr2->next) {
252 struct group *g1 = (struct group *)gr1->eptr;
253 struct group *g2 = (struct group *)gr2->eptr;
256 0 == strcmp (g1->gr_name, g2->gr_name) &&
257 0 == strcmp (g1->gr_passwd, g2->gr_passwd) &&
258 g1->gr_gid == g2->gr_gid) {
259 /* Both group entries refer to the same
260 * group. It is a split group. Merge the
262 gr1 = merge_group_entries (gr1, gr2);
266 if (NULL != gr2->next) {
267 gr2->next->prev = gr2->prev;
269 /* gr2 does not start with head */
270 assert (NULL != gr2->prev);
271 gr2->prev->next = gr2->next;
274 assert (NULL != gr1);
281 * Merge the list of members of the two group entries.
283 * The commonio_entry arguments shall be group entries.
285 * You should not merge the members of two groups if they don't have the
286 * same name, password and gid.
288 * It merge the members of the second entry in the first one, and return
289 * the modified first entry on success, or NULL on failure (with errno
292 static /*@null@*/struct commonio_entry *merge_group_entries (
293 /*@null@*/ /*@returned@*/struct commonio_entry *gr1,
294 /*@null@*/struct commonio_entry *gr2)
301 size_t new_line_len, i;
302 if (NULL == gr2 || NULL == gr1) {
307 gptr1 = (struct group *)gr1->eptr;
308 gptr2 = (struct group *)gr2->eptr;
309 if (NULL == gptr2 || NULL == gptr1) {
314 /* Concatenate the 2 lines */
315 new_line_len = strlen (gr1->line) + strlen (gr2->line) +1;
316 new_line = (char *)malloc ((new_line_len + 1) * sizeof(char*));
317 if (NULL == new_line) {
321 snprintf(new_line, new_line_len, "%s\n%s", gr1->line, gr2->line);
322 new_line[new_line_len] = '\0';
324 /* Concatenate the 2 list of members */
325 for (i=0; NULL != gptr1->gr_mem[i]; i++);
327 for (i=0; NULL != gptr2->gr_mem[i]; i++) {
328 char **pmember = gptr1->gr_mem;
329 while (NULL != *pmember) {
330 if (0 == strcmp(*pmember, gptr2->gr_mem[i])) {
335 if (NULL == *pmember) {
339 new_members = (char **)malloc ( (members+1) * sizeof(char*) );
340 if (NULL == new_members) {
345 for (i=0; NULL != gptr1->gr_mem[i]; i++) {
346 new_members[i] = gptr1->gr_mem[i];
349 for (i=0; NULL != gptr2->gr_mem[i]; i++) {
350 char **pmember = new_members;
351 while (NULL != *pmember) {
352 if (0 == strcmp(*pmember, gptr2->gr_mem[i])) {
357 if (NULL == *pmember) {
358 new_members[members] = gptr2->gr_mem[i];
360 new_members[members] = NULL;
364 gr1->line = new_line;
365 gptr1->gr_mem = new_members;
371 * Scan the group database and split the groups which have more members
372 * than specified, if this is the result from a current change.
374 * Return 0 on failure (errno set) and 1 on success.
376 static int split_groups (unsigned int max_members)
378 struct commonio_entry *gr;
380 for (gr = group_db.head; NULL != gr; gr = gr->next) {
381 struct group *gptr = (struct group *)gr->eptr;
382 struct commonio_entry *new;
383 struct group *new_gptr;
384 unsigned int members = 0;
386 /* Check if this group must be split */
391 for (members = 0; NULL != gptr->gr_mem[members]; members++);
392 if (members <= max_members)
395 new = (struct commonio_entry *) malloc (sizeof *new);
400 new->eptr = group_dup(gr->eptr);
401 if (NULL == new->eptr) {
406 new_gptr = (struct group *)new->eptr;
410 /* Enforce the maximum number of members on gptr */
411 gptr->gr_mem[max_members] = NULL;
412 /* The number of members in new_gptr will be check later */
413 new_gptr->gr_mem = &new_gptr->gr_mem[max_members];
415 /* insert the new entry in the list */
417 new->next = gr->next;