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 - 2010, 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.
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;
84 || (valid_field (gr->gr_name, ":\n") == -1)
85 || (valid_field (gr->gr_passwd, ":\n") == -1)
86 || (gr->gr_gid == (gid_t)-1)) {
90 /* FIXME: fail also if gr->gr_mem == NULL ?*/
91 if (NULL != gr->gr_mem) {
93 for (i = 0; NULL != gr->gr_mem[i]; i++) {
94 if (valid_field (gr->gr_mem[i], ",:\n") == -1) {
100 return (putgrent (gr, file) == -1) ? -1 : 0;
103 static int group_close_hook (void)
105 unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
107 if (0 == max_members) {
111 return split_groups (max_members);
114 static struct commonio_ops group_ops = {
126 static /*@owned@*/struct commonio_db group_db = {
127 GROUP_FILE, /* filename */
128 &group_ops, /* ops */
142 int gr_setdbname (const char *filename)
144 return commonio_setname (&group_db, filename);
147 /*@observer@*/const char *gr_dbname (void)
149 return group_db.filename;
154 return commonio_lock (&group_db);
157 int gr_open (int mode)
159 return commonio_open (&group_db, mode);
162 /*@observer@*/ /*@null@*/const struct group *gr_locate (const char *name)
164 return commonio_locate (&group_db, name);
167 /*@observer@*/ /*@null@*/const struct group *gr_locate_gid (gid_t gid)
169 const struct group *grp;
172 while ( ((grp = gr_next ()) != NULL)
173 && (grp->gr_gid != gid)) {
179 int gr_update (const struct group *gr)
181 return commonio_update (&group_db, (const void *) gr);
184 int gr_remove (const char *name)
186 return commonio_remove (&group_db, name);
191 return commonio_rewind (&group_db);
194 /*@observer@*/ /*@null@*/const struct group *gr_next (void)
196 return commonio_next (&group_db);
201 return commonio_close (&group_db);
206 return commonio_unlock (&group_db);
209 void __gr_set_changed (void)
211 group_db.changed = true;
214 /*@dependent@*/ /*@null@*/struct commonio_entry *__gr_get_head (void)
216 return group_db.head;
219 /*@observer@*/const struct commonio_db *__gr_get_db (void)
224 void __gr_del_entry (const struct commonio_entry *ent)
226 commonio_del_entry (&group_db, ent);
229 static int gr_cmp (const void *p1, const void *p2)
233 if ((*(struct commonio_entry **) p1)->eptr == NULL) {
236 if ((*(struct commonio_entry **) p2)->eptr == NULL) {
240 u1 = ((struct group *) (*(struct commonio_entry **) p1)->eptr)->gr_gid;
241 u2 = ((struct group *) (*(struct commonio_entry **) p2)->eptr)->gr_gid;
245 } else if (u1 > u2) {
252 /* Sort entries by GID */
255 return commonio_sort (&group_db, gr_cmp);
258 static int group_open_hook (void)
260 unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
261 struct commonio_entry *gr1, *gr2;
263 if (0 == max_members) {
267 for (gr1 = group_db.head; NULL != gr1; gr1 = gr1->next) {
268 for (gr2 = gr1->next; NULL != gr2; gr2 = gr2->next) {
269 struct group *g1 = (struct group *)gr1->eptr;
270 struct group *g2 = (struct group *)gr2->eptr;
273 0 == strcmp (g1->gr_name, g2->gr_name) &&
274 0 == strcmp (g1->gr_passwd, g2->gr_passwd) &&
275 g1->gr_gid == g2->gr_gid) {
276 /* Both group entries refer to the same
277 * group. It is a split group. Merge the
279 gr1 = merge_group_entries (gr1, gr2);
283 if (NULL != gr2->next) {
284 gr2->next->prev = gr2->prev;
286 /* gr2 does not start with head */
287 assert (NULL != gr2->prev);
288 gr2->prev->next = gr2->next;
291 assert (NULL != gr1);
298 * Merge the list of members of the two group entries.
300 * The commonio_entry arguments shall be group entries.
302 * You should not merge the members of two groups if they don't have the
303 * same name, password and gid.
305 * It merge the members of the second entry in the first one, and return
306 * the modified first entry on success, or NULL on failure (with errno
309 static /*@null@*/struct commonio_entry *merge_group_entries (
310 /*@null@*/ /*@returned@*/struct commonio_entry *gr1,
311 /*@null@*/struct commonio_entry *gr2)
318 size_t new_line_len, i;
319 if (NULL == gr2 || NULL == gr1) {
324 gptr1 = (struct group *)gr1->eptr;
325 gptr2 = (struct group *)gr2->eptr;
326 if (NULL == gptr2 || NULL == gptr1) {
331 /* Concatenate the 2 lines */
332 new_line_len = strlen (gr1->line) + strlen (gr2->line) +1;
333 new_line = (char *)malloc ((new_line_len + 1) * sizeof(char*));
334 if (NULL == new_line) {
338 snprintf(new_line, new_line_len, "%s\n%s", gr1->line, gr2->line);
339 new_line[new_line_len] = '\0';
341 /* Concatenate the 2 list of members */
342 for (i=0; NULL != gptr1->gr_mem[i]; i++);
344 for (i=0; NULL != gptr2->gr_mem[i]; i++) {
345 char **pmember = gptr1->gr_mem;
346 while (NULL != *pmember) {
347 if (0 == strcmp(*pmember, gptr2->gr_mem[i])) {
352 if (NULL == *pmember) {
356 new_members = (char **)malloc ( (members+1) * sizeof(char*) );
357 if (NULL == new_members) {
362 for (i=0; NULL != gptr1->gr_mem[i]; i++) {
363 new_members[i] = gptr1->gr_mem[i];
366 for (i=0; NULL != gptr2->gr_mem[i]; i++) {
367 char **pmember = new_members;
368 while (NULL != *pmember) {
369 if (0 == strcmp(*pmember, gptr2->gr_mem[i])) {
374 if (NULL == *pmember) {
375 new_members[members] = gptr2->gr_mem[i];
377 new_members[members] = NULL;
381 gr1->line = new_line;
382 gptr1->gr_mem = new_members;
388 * Scan the group database and split the groups which have more members
389 * than specified, if this is the result from a current change.
391 * Return 0 on failure (errno set) and 1 on success.
393 static int split_groups (unsigned int max_members)
395 struct commonio_entry *gr;
397 for (gr = group_db.head; NULL != gr; gr = gr->next) {
398 struct group *gptr = (struct group *)gr->eptr;
399 struct commonio_entry *new;
400 struct group *new_gptr;
401 unsigned int members = 0;
404 /* Check if this group must be split */
411 for (members = 0; NULL != gptr->gr_mem[members]; members++);
412 if (members <= max_members) {
416 new = (struct commonio_entry *) malloc (sizeof *new);
421 new->eptr = group_dup(gr->eptr);
422 if (NULL == new->eptr) {
427 new_gptr = (struct group *)new->eptr;
431 /* Enforce the maximum number of members on gptr */
432 for (i = max_members; NULL != gptr->gr_mem[i]; i++) {
433 free (gptr->gr_mem[i]);
434 gptr->gr_mem[i] = NULL;
436 /* Shift all the members */
437 /* The number of members in new_gptr will be check later */
438 for (i = 0; NULL != new_gptr->gr_mem[i + max_members]; i++) {
439 if (NULL != new_gptr->gr_mem[i]) {
440 free (new_gptr->gr_mem[i]);
442 new_gptr->gr_mem[i] = new_gptr->gr_mem[i + max_members];
443 new_gptr->gr_mem[i + max_members] = NULL;
445 for (; NULL != new_gptr->gr_mem[i]; i++) {
446 free (new_gptr->gr_mem[i]);
447 new_gptr->gr_mem[i] = NULL;
450 /* insert the new entry in the list */
452 new->next = gr->next;