6 #include "prototypes.h"
11 extern int putgrent (const struct group *, FILE *);
12 extern struct group *sgetgrent (const char *);
14 static struct commonio_entry *merge_group_entries (struct commonio_entry *,
15 struct commonio_entry *);
16 static int split_groups (unsigned int);
17 static int group_open_hook (void);
19 static void *group_dup (const void *ent)
21 const struct group *gr = ent;
26 static void group_free (void *ent)
28 struct group *gr = ent;
32 while (*(gr->gr_mem)) {
39 static const char *group_getname (const void *ent)
41 const struct group *gr = ent;
46 static void *group_parse (const char *line)
48 return (void *) sgetgrent (line);
51 static int group_put (const void *ent, FILE * file)
53 const struct group *gr = ent;
55 return (putgrent (gr, file) == -1) ? -1 : 0;
58 static int group_close_hook (void)
60 unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
65 return split_groups (max_members);
68 static struct commonio_ops group_ops = {
80 static struct commonio_db group_db = {
81 GROUP_FILE, /* filename */
96 int gr_name (const char *filename)
98 return commonio_setname (&group_db, filename);
103 return commonio_lock (&group_db);
106 int gr_open (int mode)
108 return commonio_open (&group_db, mode);
111 const struct group *gr_locate (const char *name)
113 return commonio_locate (&group_db, name);
116 int gr_update (const struct group *gr)
118 return commonio_update (&group_db, (const void *) gr);
121 int gr_remove (const char *name)
123 return commonio_remove (&group_db, name);
128 return commonio_rewind (&group_db);
131 const struct group *gr_next (void)
133 return commonio_next (&group_db);
138 return commonio_close (&group_db);
143 return commonio_unlock (&group_db);
146 void __gr_set_changed (void)
148 group_db.changed = 1;
151 struct commonio_entry *__gr_get_head (void)
153 return group_db.head;
156 struct commonio_db *__gr_get_db (void)
161 void __gr_del_entry (const struct commonio_entry *ent)
163 commonio_del_entry (&group_db, ent);
166 static int gr_cmp (const void *p1, const void *p2)
170 if ((*(struct commonio_entry **) p1)->eptr == NULL)
172 if ((*(struct commonio_entry **) p2)->eptr == NULL)
175 u1 = ((struct group *) (*(struct commonio_entry **) p1)->eptr)->gr_gid;
176 u2 = ((struct group *) (*(struct commonio_entry **) p2)->eptr)->gr_gid;
186 /* Sort entries by GID */
189 return commonio_sort (&group_db, gr_cmp);
192 static int group_open_hook (void)
194 unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
195 struct commonio_entry *gr1, *gr2;
197 if (0 == max_members)
200 for (gr1 = group_db.head; gr1; gr1 = gr1->next) {
201 for (gr2 = gr1->next; gr2; gr2 = gr2->next) {
202 struct group *g1 = (struct group *)gr1->eptr;
203 struct group *g2 = (struct group *)gr2->eptr;
206 0 == strcmp (g1->gr_name, g2->gr_name) &&
207 0 == strcmp (g1->gr_passwd, g2->gr_passwd) &&
208 g1->gr_gid == g2->gr_gid) {
209 /* Both group entries refer to the same
210 * group. It is a split group. Merge the
212 gr1 = merge_group_entries (gr1, gr2);
216 if (NULL != gr2->next)
217 gr2->next->prev = gr2->prev;
218 gr2->prev->next = gr2->next;
227 * Merge the list of members of the two group entries.
229 * The commonio_entry arguments shall be group entries.
231 * You should not merge the members of two groups if they don't have the
232 * same name, password and gid.
234 * It merge the members of the second entry in the first one, and return
235 * the modified first entry on success, or NUll on failure (with errno
238 static struct commonio_entry *merge_group_entries (struct commonio_entry *gr1,
239 struct commonio_entry *gr2)
247 if (NULL == gr2 || NULL == gr1) {
252 gptr1 = (struct group *)gr1->eptr;
253 gptr2 = (struct group *)gr2->eptr;
254 if (NULL == gptr2 || NULL == gptr1) {
259 /* Concatenate the 2 lines */
260 new_line_len = strlen (gr1->line) + strlen (gr2->line) +1;
261 new_line = (char *)malloc ((new_line_len + 1) * sizeof(char*));
262 if (NULL == new_line) {
266 snprintf(new_line, new_line_len, "%s\n%s", gr1->line, gr2->line);
267 new_line[new_line_len] = '\0';
269 /* Concatenate the 2 list of members */
270 for (i=0; NULL != gptr1->gr_mem[i]; i++);
272 for (i=0; NULL != gptr2->gr_mem[i]; i++) {
273 char **pmember = gptr1->gr_mem;
274 while (NULL != *pmember) {
275 if (0 == strcmp(*pmember, gptr2->gr_mem[i]))
279 if (NULL == *pmember)
282 new_members = (char **)malloc ( (members+1) * sizeof(char*) );
283 if (NULL == new_members) {
287 for (i=0; NULL != gptr1->gr_mem[i]; i++)
288 new_members[i] = gptr1->gr_mem[i];
290 for (i=0; NULL != gptr2->gr_mem[i]; i++) {
291 char **pmember = new_members;
292 while (NULL != *pmember) {
293 if (0 == strcmp(*pmember, gptr2->gr_mem[i]))
297 if (NULL == *pmember) {
298 new_members[members++] = gptr2->gr_mem[i];
299 new_members[members] = NULL;
303 gr1->line = new_line;
304 gptr1->gr_mem = new_members;
310 * Scan the group database and split the groups which have more members
311 * than specified, if this is the result from a current change.
313 * Return 0 on failure (errno set) and 1 on success.
315 static int split_groups (unsigned int max_members)
317 struct commonio_entry *gr;
319 for (gr = group_db.head; gr; gr = gr->next) {
320 struct group *gptr = (struct group *)gr->eptr;
321 struct commonio_entry *new;
322 struct group *new_gptr;
323 unsigned int members = 0;
325 /* Check if this group must be split */
330 for (members = 0; NULL != gptr->gr_mem[members]; members++);
331 if (members <= max_members)
334 new = (struct commonio_entry *) malloc (sizeof *new);
339 new->eptr = group_dup(gr->eptr);
340 if (NULL == new->eptr) {
344 new_gptr = (struct group *)new->eptr;
348 /* Enforce the maximum number of members on gptr */
349 gptr->gr_mem[max_members] = NULL;
350 /* The number of members in new_gptr will be check later */
351 new_gptr->gr_mem = &new_gptr->gr_mem[max_members];
353 /* insert the new entry in the list */
355 new->next = gr->next;