Require binutils 2.24 to build x86-64 glibc [BZ #20139]
[glibc.git] / grp / grp-merge.c
blob0a1eb38d2c96bf7ad8f82c5668ac035512506b6a
1 /* Group merging implementation.
2 Copyright (C) 2016 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <grp.h>
23 #include <grp-merge.h>
25 #define BUFCHECK(size) \
26 ({ \
27 do \
28 { \
29 if (c + (size) > buflen) \
30 { \
31 free (members); \
32 return ERANGE; \
33 } \
34 } \
35 while (0); \
38 int
39 internal_function
40 __copy_grp (const struct group srcgrp, const size_t buflen,
41 struct group *destgrp, char *destbuf, char **endptr)
43 size_t i;
44 size_t c = 0;
45 size_t len;
46 size_t memcount;
47 char **members = NULL;
49 /* Copy the GID. */
50 destgrp->gr_gid = srcgrp.gr_gid;
52 /* Copy the name. */
53 len = strlen (srcgrp.gr_name) + 1;
54 BUFCHECK (len);
55 memcpy (&destbuf[c], srcgrp.gr_name, len);
56 destgrp->gr_name = &destbuf[c];
57 c += len;
59 /* Copy the password. */
60 len = strlen (srcgrp.gr_passwd) + 1;
61 BUFCHECK (len);
62 memcpy (&destbuf[c], srcgrp.gr_passwd, len);
63 destgrp->gr_passwd = &destbuf[c];
64 c += len;
66 /* Count all of the members. */
67 for (memcount = 0; srcgrp.gr_mem[memcount]; memcount++)
70 /* Allocate a temporary holding area for the pointers to the member
71 contents, including space for a NULL-terminator. */
72 members = malloc (sizeof (char *) * (memcount + 1));
73 if (members == NULL)
74 return ENOMEM;
76 /* Copy all of the group members to destbuf and add a pointer to each of
77 them into the 'members' array. */
78 for (i = 0; srcgrp.gr_mem[i]; i++)
80 len = strlen (srcgrp.gr_mem[i]) + 1;
81 BUFCHECK (len);
82 memcpy (&destbuf[c], srcgrp.gr_mem[i], len);
83 members[i] = &destbuf[c];
84 c += len;
86 members[i] = NULL;
88 /* Copy the pointers from the members array into the buffer and assign them
89 to the gr_mem member of destgrp. */
90 destgrp->gr_mem = (char **) &destbuf[c];
91 len = sizeof (char *) * (memcount + 1);
92 BUFCHECK (len);
93 memcpy (&destbuf[c], members, len);
94 c += len;
95 free (members);
96 members = NULL;
98 /* Save the count of members at the end. */
99 BUFCHECK (sizeof (size_t));
100 memcpy (&destbuf[c], &memcount, sizeof (size_t));
101 c += sizeof (size_t);
103 if (endptr)
104 *endptr = destbuf + c;
105 return 0;
107 libc_hidden_def (__copy_grp)
109 /* Check that the name, GID and passwd fields match, then
110 copy in the gr_mem array. */
112 internal_function
113 __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
114 size_t buflen, struct group *mergegrp, char *mergebuf)
116 size_t c, i, len;
117 size_t savedmemcount;
118 size_t memcount;
119 size_t membersize;
120 char **members = NULL;
122 /* We only support merging members of groups with identical names and
123 GID values. If we hit this case, we need to overwrite the current
124 buffer with the saved one (which is functionally equivalent to
125 treating the new lookup as NSS_STATUS_NOTFOUND). */
126 if (mergegrp->gr_gid != savedgrp->gr_gid
127 || strcmp (mergegrp->gr_name, savedgrp->gr_name))
128 return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
130 /* Get the count of group members from the last sizeof (size_t) bytes in the
131 mergegrp buffer. */
132 savedmemcount = (size_t) *(savedend - sizeof (size_t));
134 /* Get the count of new members to add. */
135 for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++)
138 /* Create a temporary array to hold the pointers to the member values from
139 both the saved and merge groups. */
140 membersize = savedmemcount + memcount + 1;
141 members = malloc (sizeof (char *) * membersize);
142 if (members == NULL)
143 return ENOMEM;
145 /* Copy in the existing member pointers from the saved group
146 Note: this is not NULL-terminated yet. */
147 memcpy (members, savedgrp->gr_mem, sizeof (char *) * savedmemcount);
149 /* Back up into the savedbuf until we get back to the NULL-terminator of the
150 group member list. (This means walking back savedmemcount + 1 (char *) pointers
151 and the member count value.
152 The value of c is going to be the used length of the buffer backed up by
153 the member count and further backed up by the size of the pointers. */
154 c = savedend - savedbuf
155 - sizeof (size_t)
156 - sizeof (char *) * (savedmemcount + 1);
158 /* Add all the new group members, overwriting the old NULL-terminator while
159 adding the new pointers to the temporary array. */
160 for (i = 0; mergegrp->gr_mem[i]; i++)
162 len = strlen (mergegrp->gr_mem[i]) + 1;
163 BUFCHECK (len);
164 memcpy (&savedbuf[c], mergegrp->gr_mem[i], len);
165 members[savedmemcount + i] = &savedbuf[c];
166 c += len;
168 /* Add the NULL-terminator. */
169 members[savedmemcount + memcount] = NULL;
171 /* Copy the member array back into the buffer after the member list and free
172 the member array. */
173 savedgrp->gr_mem = (char **) &savedbuf[c];
174 len = sizeof (char *) * membersize;
175 BUFCHECK (len);
176 memcpy (&savedbuf[c], members, len);
177 c += len;
179 free (members);
180 members = NULL;
182 /* Finally, copy the results back into mergebuf, since that's the buffer
183 that we were provided by the caller. */
184 return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
186 libc_hidden_def (__merge_grp)