]> granicus.if.org Git - shadow/blob - lib/groupio.c
(split_groups): Test the pointer returned by malloc.
[shadow] / lib / groupio.c
1
2 #include <config.h>
3
4 #ident "$Id$"
5
6 #include "prototypes.h"
7 #include "defines.h"
8 #include "commonio.h"
9 #include "getdef.h"
10 #include "groupio.h"
11 extern int putgrent (const struct group *, FILE *);
12 extern struct group *sgetgrent (const char *);
13
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);
18
19 static void *group_dup (const void *ent)
20 {
21         const struct group *gr = ent;
22
23         return __gr_dup (gr);
24 }
25
26 static void group_free (void *ent)
27 {
28         struct group *gr = ent;
29
30         free (gr->gr_name);
31         free (gr->gr_passwd);
32         while (*(gr->gr_mem)) {
33                 free (*(gr->gr_mem));
34                 gr->gr_mem++;
35         }
36         free (gr);
37 }
38
39 static const char *group_getname (const void *ent)
40 {
41         const struct group *gr = ent;
42
43         return gr->gr_name;
44 }
45
46 static void *group_parse (const char *line)
47 {
48         return (void *) sgetgrent (line);
49 }
50
51 static int group_put (const void *ent, FILE * file)
52 {
53         const struct group *gr = ent;
54
55         return (putgrent (gr, file) == -1) ? -1 : 0;
56 }
57
58 static int group_close_hook (void)
59 {
60         unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
61
62         if (0 == max_members)
63                 return 1;
64
65         return split_groups (max_members);
66 }
67
68 static struct commonio_ops group_ops = {
69         group_dup,
70         group_free,
71         group_getname,
72         group_parse,
73         group_put,
74         fgetsx,
75         fputsx,
76         group_open_hook,
77         group_close_hook
78 };
79
80 static struct commonio_db group_db = {
81         GROUP_FILE,             /* filename */
82         &group_ops,             /* ops */
83         NULL,                   /* fp */
84 #ifdef WITH_SELINUX
85         NULL,                   /* scontext */
86 #endif
87         NULL,                   /* head */
88         NULL,                   /* tail */
89         NULL,                   /* cursor */
90         0,                      /* changed */
91         0,                      /* isopen */
92         0,                      /* locked */
93         0                       /* readonly */
94 };
95
96 int gr_name (const char *filename)
97 {
98         return commonio_setname (&group_db, filename);
99 }
100
101 int gr_lock (void)
102 {
103         return commonio_lock (&group_db);
104 }
105
106 int gr_open (int mode)
107 {
108         return commonio_open (&group_db, mode);
109 }
110
111 const struct group *gr_locate (const char *name)
112 {
113         return commonio_locate (&group_db, name);
114 }
115
116 int gr_update (const struct group *gr)
117 {
118         return commonio_update (&group_db, (const void *) gr);
119 }
120
121 int gr_remove (const char *name)
122 {
123         return commonio_remove (&group_db, name);
124 }
125
126 int gr_rewind (void)
127 {
128         return commonio_rewind (&group_db);
129 }
130
131 const struct group *gr_next (void)
132 {
133         return commonio_next (&group_db);
134 }
135
136 int gr_close (void)
137 {
138         return commonio_close (&group_db);
139 }
140
141 int gr_unlock (void)
142 {
143         return commonio_unlock (&group_db);
144 }
145
146 void __gr_set_changed (void)
147 {
148         group_db.changed = 1;
149 }
150
151 struct commonio_entry *__gr_get_head (void)
152 {
153         return group_db.head;
154 }
155
156 struct commonio_db *__gr_get_db (void)
157 {
158         return &group_db;
159 }
160
161 void __gr_del_entry (const struct commonio_entry *ent)
162 {
163         commonio_del_entry (&group_db, ent);
164 }
165
166 static int gr_cmp (const void *p1, const void *p2)
167 {
168         gid_t u1, u2;
169
170         if ((*(struct commonio_entry **) p1)->eptr == NULL)
171                 return 1;
172         if ((*(struct commonio_entry **) p2)->eptr == NULL)
173                 return -1;
174
175         u1 = ((struct group *) (*(struct commonio_entry **) p1)->eptr)->gr_gid;
176         u2 = ((struct group *) (*(struct commonio_entry **) p2)->eptr)->gr_gid;
177
178         if (u1 < u2)
179                 return -1;
180         else if (u1 > u2)
181                 return 1;
182         else
183                 return 0;
184 }
185
186 /* Sort entries by GID */
187 int gr_sort ()
188 {
189         return commonio_sort (&group_db, gr_cmp);
190 }
191
192 static int group_open_hook (void)
193 {
194         unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
195         struct commonio_entry *gr1, *gr2;
196
197         if (0 == max_members)
198                 return 1;
199
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;
204                         if (NULL != g1 &&
205                             NULL != g2 &&
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
211                                  * members. */
212                                 gr1 = merge_group_entries (gr1, gr2);
213                                 if (NULL == gr1)
214                                         return 0;
215                                 /* Unlink gr2 */
216                                 if (NULL != gr2->next)
217                                         gr2->next->prev = gr2->prev;
218                                 gr2->prev->next = gr2->next;
219                         }
220                 }
221         }
222
223         return 1;
224 }
225
226 /*
227  * Merge the list of members of the two group entries.
228  *
229  * The commonio_entry arguments shall be group entries.
230  *
231  * You should not merge the members of two groups if they don't have the
232  * same name, password and gid.
233  *
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
236  * set).
237  */
238 static struct commonio_entry *merge_group_entries (struct commonio_entry *gr1,
239                                                    struct commonio_entry *gr2)
240 {
241         struct group *gptr1;
242         struct group *gptr2;
243         char **new_members;
244         int members = 0;
245         char *new_line;
246         int new_line_len, i;
247         if (NULL == gr2 || NULL == gr1) {
248                 errno = EINVAL;
249                 return NULL;
250         }
251
252         gptr1 = (struct group *)gr1->eptr;
253         gptr2 = (struct group *)gr2->eptr;
254         if (NULL == gptr2 || NULL == gptr1) {
255                 errno = EINVAL;
256                 return NULL;
257         }
258
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) {
263                 errno = ENOMEM;
264                 return NULL;
265         }
266         snprintf(new_line, new_line_len, "%s\n%s", gr1->line, gr2->line);
267         new_line[new_line_len] = '\0';
268
269         /* Concatenate the 2 list of members */
270         for (i=0; NULL != gptr1->gr_mem[i]; i++);
271         members += 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]))
276                                 break;
277                         pmember++;
278                 }
279                 if (NULL == *pmember)
280                         members++;
281         }
282         new_members = (char **)malloc ( (members+1) * sizeof(char*) );
283         if (NULL == new_members) {
284                 errno = ENOMEM;
285                 return NULL;
286         }
287         for (i=0; NULL != gptr1->gr_mem[i]; i++)
288                 new_members[i] = gptr1->gr_mem[i];
289         members = 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]))
294                                 break;
295                         pmember++;
296                 }
297                 if (NULL == *pmember) {
298                         new_members[members++] = gptr2->gr_mem[i];
299                         new_members[members] = NULL;
300                 }
301         }
302
303         gr1->line = new_line;
304         gptr1->gr_mem = new_members;
305
306         return gr1;
307 }
308
309 /*
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.
312  *
313  * Return 0 on failure (errno set) and 1 on success.
314  */
315 static int split_groups (unsigned int max_members)
316 {
317         struct commonio_entry *gr;
318
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;
324
325                 /* Check if this group must be split */
326                 if (!gr->changed)
327                         continue;
328                 if (NULL == gptr)
329                         continue;
330                 for (members = 0; NULL != gptr->gr_mem[members]; members++);
331                 if (members <= max_members)
332                         continue;
333
334                 new = (struct commonio_entry *) malloc (sizeof *new);
335                 if (NULL == new) {
336                         errno = ENOMEM;
337                         return 0;
338                 }
339                 new->eptr = group_dup(gr->eptr);
340                 if (NULL == new->eptr) {
341                         errno = ENOMEM;
342                         return 0;
343                 }
344                 new_gptr = (struct group *)new->eptr;
345                 new->line = NULL;
346                 new->changed = 1;
347
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];
352
353                 /* insert the new entry in the list */
354                 new->prev = gr;
355                 new->next = gr->next;
356                 gr->next = new;
357         }
358
359         return 1;
360 }
361