]> granicus.if.org Git - shadow/blob - lib/groupio.c
* src/newusers.c: Fix typo.
[shadow] / lib / groupio.c
1 /*
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
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
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.
20  *
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.
32  */
33
34 #include <config.h>
35
36 #ident "$Id$"
37
38 #include <assert.h>
39 #include <stdio.h>
40
41 #include "prototypes.h"
42 #include "defines.h"
43 #include "commonio.h"
44 #include "getdef.h"
45 #include "groupio.h"
46
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);
52
53 static /*@null@*/ /*@only@*/void *group_dup (const void *ent)
54 {
55         const struct group *gr = ent;
56
57         return __gr_dup (gr);
58 }
59
60 static void group_free (/*@out@*/ /*@only@*/void *ent)
61 {
62         struct group *gr = ent;
63
64         gr_free (gr);
65 }
66
67 static const char *group_getname (const void *ent)
68 {
69         const struct group *gr = ent;
70
71         return gr->gr_name;
72 }
73
74 static void *group_parse (const char *line)
75 {
76         return (void *) sgetgrent (line);
77 }
78
79 static int group_put (const void *ent, FILE * file)
80 {
81         const struct group *gr = ent;
82
83         if (   (NULL == gr)
84             || (valid_field (gr->gr_name, ":\n") == -1)
85             || (valid_field (gr->gr_passwd, ":\n") == -1)
86             || (gr->gr_gid == (gid_t)-1)) {
87                 return -1;
88         }
89
90         /* FIXME: fail also if gr->gr_mem == NULL ?*/
91         if (NULL != gr->gr_mem) {
92                 size_t i;
93                 for (i = 0; NULL != gr->gr_mem[i]; i++) {
94                         if (valid_field (gr->gr_mem[i], ",:\n") == -1) {
95                                 return -1;
96                         }
97                 }
98         }
99
100         return (putgrent (gr, file) == -1) ? -1 : 0;
101 }
102
103 static int group_close_hook (void)
104 {
105         unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
106
107         if (0 == max_members) {
108                 return 1;
109         }
110
111         return split_groups (max_members);
112 }
113
114 static struct commonio_ops group_ops = {
115         group_dup,
116         group_free,
117         group_getname,
118         group_parse,
119         group_put,
120         fgetsx,
121         fputsx,
122         group_open_hook,
123         group_close_hook
124 };
125
126 static /*@owned@*/struct commonio_db group_db = {
127         GROUP_FILE,             /* filename */
128         &group_ops,             /* ops */
129         NULL,                   /* fp */
130 #ifdef WITH_SELINUX
131         NULL,                   /* scontext */
132 #endif
133         NULL,                   /* head */
134         NULL,                   /* tail */
135         NULL,                   /* cursor */
136         false,                  /* changed */
137         false,                  /* isopen */
138         false,                  /* locked */
139         false                   /* readonly */
140 };
141
142 int gr_setdbname (const char *filename)
143 {
144         return commonio_setname (&group_db, filename);
145 }
146
147 /*@observer@*/const char *gr_dbname (void)
148 {
149         return group_db.filename;
150 }
151
152 int gr_lock (void)
153 {
154         return commonio_lock (&group_db);
155 }
156
157 int gr_open (int mode)
158 {
159         return commonio_open (&group_db, mode);
160 }
161
162 /*@observer@*/ /*@null@*/const struct group *gr_locate (const char *name)
163 {
164         return commonio_locate (&group_db, name);
165 }
166
167 /*@observer@*/ /*@null@*/const struct group *gr_locate_gid (gid_t gid)
168 {
169         const struct group *grp;
170
171         gr_rewind ();
172         while (   ((grp = gr_next ()) != NULL)
173                && (grp->gr_gid != gid)) {
174         }
175
176         return grp;
177 }
178
179 int gr_update (const struct group *gr)
180 {
181         return commonio_update (&group_db, (const void *) gr);
182 }
183
184 int gr_remove (const char *name)
185 {
186         return commonio_remove (&group_db, name);
187 }
188
189 int gr_rewind (void)
190 {
191         return commonio_rewind (&group_db);
192 }
193
194 /*@observer@*/ /*@null@*/const struct group *gr_next (void)
195 {
196         return commonio_next (&group_db);
197 }
198
199 int gr_close (void)
200 {
201         return commonio_close (&group_db);
202 }
203
204 int gr_unlock (void)
205 {
206         return commonio_unlock (&group_db);
207 }
208
209 void __gr_set_changed (void)
210 {
211         group_db.changed = true;
212 }
213
214 /*@dependent@*/ /*@null@*/struct commonio_entry *__gr_get_head (void)
215 {
216         return group_db.head;
217 }
218
219 /*@observer@*/const struct commonio_db *__gr_get_db (void)
220 {
221         return &group_db;
222 }
223
224 void __gr_del_entry (const struct commonio_entry *ent)
225 {
226         commonio_del_entry (&group_db, ent);
227 }
228
229 static int gr_cmp (const void *p1, const void *p2)
230 {
231         gid_t u1, u2;
232
233         if ((*(struct commonio_entry **) p1)->eptr == NULL) {
234                 return 1;
235         }
236         if ((*(struct commonio_entry **) p2)->eptr == NULL) {
237                 return -1;
238         }
239
240         u1 = ((struct group *) (*(struct commonio_entry **) p1)->eptr)->gr_gid;
241         u2 = ((struct group *) (*(struct commonio_entry **) p2)->eptr)->gr_gid;
242
243         if (u1 < u2) {
244                 return -1;
245         } else if (u1 > u2) {
246                 return 1;
247         } else {
248                 return 0;
249         }
250 }
251
252 /* Sort entries by GID */
253 int gr_sort ()
254 {
255         return commonio_sort (&group_db, gr_cmp);
256 }
257
258 static int group_open_hook (void)
259 {
260         unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
261         struct commonio_entry *gr1, *gr2;
262
263         if (0 == max_members) {
264                 return 1;
265         }
266
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;
271                         if (NULL != g1 &&
272                             NULL != g2 &&
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
278                                  * members. */
279                                 gr1 = merge_group_entries (gr1, gr2);
280                                 if (NULL == gr1)
281                                         return 0;
282                                 /* Unlink gr2 */
283                                 if (NULL != gr2->next) {
284                                         gr2->next->prev = gr2->prev;
285                                 }
286                                 /* gr2 does not start with head */
287                                 assert (NULL != gr2->prev);
288                                 gr2->prev->next = gr2->next;
289                         }
290                 }
291                 assert (NULL != gr1);
292         }
293
294         return 1;
295 }
296
297 /*
298  * Merge the list of members of the two group entries.
299  *
300  * The commonio_entry arguments shall be group entries.
301  *
302  * You should not merge the members of two groups if they don't have the
303  * same name, password and gid.
304  *
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
307  * set).
308  */
309 static /*@null@*/struct commonio_entry *merge_group_entries (
310         /*@null@*/ /*@returned@*/struct commonio_entry *gr1,
311         /*@null@*/struct commonio_entry *gr2)
312 {
313         struct group *gptr1;
314         struct group *gptr2;
315         char **new_members;
316         size_t members = 0;
317         char *new_line;
318         size_t new_line_len, i;
319         if (NULL == gr2 || NULL == gr1) {
320                 errno = EINVAL;
321                 return NULL;
322         }
323
324         gptr1 = (struct group *)gr1->eptr;
325         gptr2 = (struct group *)gr2->eptr;
326         if (NULL == gptr2 || NULL == gptr1) {
327                 errno = EINVAL;
328                 return NULL;
329         }
330
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) {
335                 errno = ENOMEM;
336                 return NULL;
337         }
338         snprintf(new_line, new_line_len, "%s\n%s", gr1->line, gr2->line);
339         new_line[new_line_len] = '\0';
340
341         /* Concatenate the 2 list of members */
342         for (i=0; NULL != gptr1->gr_mem[i]; i++);
343         members += 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])) {
348                                 break;
349                         }
350                         pmember++;
351                 }
352                 if (NULL == *pmember) {
353                         members++;
354                 }
355         }
356         new_members = (char **)malloc ( (members+1) * sizeof(char*) );
357         if (NULL == new_members) {
358                 free (new_line);
359                 errno = ENOMEM;
360                 return NULL;
361         }
362         for (i=0; NULL != gptr1->gr_mem[i]; i++) {
363                 new_members[i] = gptr1->gr_mem[i];
364         }
365         members = 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])) {
370                                 break;
371                         }
372                         pmember++;
373                 }
374                 if (NULL == *pmember) {
375                         new_members[members] = gptr2->gr_mem[i];
376                         members++;
377                         new_members[members] = NULL;
378                 }
379         }
380
381         gr1->line = new_line;
382         gptr1->gr_mem = new_members;
383
384         return gr1;
385 }
386
387 /*
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.
390  *
391  * Return 0 on failure (errno set) and 1 on success.
392  */
393 static int split_groups (unsigned int max_members)
394 {
395         struct commonio_entry *gr;
396
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;
402                 unsigned int i;
403
404                 /* Check if this group must be split */
405                 if (!gr->changed) {
406                         continue;
407                 }
408                 if (NULL == gptr) {
409                         continue;
410                 }
411                 for (members = 0; NULL != gptr->gr_mem[members]; members++);
412                 if (members <= max_members) {
413                         continue;
414                 }
415
416                 new = (struct commonio_entry *) malloc (sizeof *new);
417                 if (NULL == new) {
418                         errno = ENOMEM;
419                         return 0;
420                 }
421                 new->eptr = group_dup(gr->eptr);
422                 if (NULL == new->eptr) {
423                         free (new);
424                         errno = ENOMEM;
425                         return 0;
426                 }
427                 new_gptr = (struct group *)new->eptr;
428                 new->line = NULL;
429                 new->changed = true;
430
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;
435                 }
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]);
441                         }
442                         new_gptr->gr_mem[i] = new_gptr->gr_mem[i + max_members];
443                         new_gptr->gr_mem[i + max_members] = NULL;
444                 }
445                 for (; NULL != new_gptr->gr_mem[i]; i++) {
446                         free (new_gptr->gr_mem[i]);
447                         new_gptr->gr_mem[i] = NULL;
448                 }
449
450                 /* insert the new entry in the list */
451                 new->prev = gr;
452                 new->next = gr->next;
453                 gr->next = new;
454         }
455
456         return 1;
457 }
458