Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2009 Ted Percival
5 : :
6 : : PulseAudio is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU Lesser General Public License as
8 : : published by the Free Software Foundation; either version 2.1 of the
9 : : License, or (at your option) any later version.
10 : :
11 : : PulseAudio is distributed in the hope that it will be useful, but
12 : : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : Lesser General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU Lesser General Public
17 : : License along with PulseAudio; if not, write to the Free Software
18 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 : : USA.
20 : : ***/
21 : :
22 : : #ifdef HAVE_CONFIG_H
23 : : #include <config.h>
24 : : #endif
25 : :
26 : : #include <sys/types.h>
27 : : #include <errno.h>
28 : :
29 : : #ifdef HAVE_PWD_H
30 : : #include <pwd.h>
31 : : #endif
32 : :
33 : : #ifdef HAVE_GRP_H
34 : : #include <grp.h>
35 : : #endif
36 : :
37 : : #include <pulse/xmalloc.h>
38 : : #include <pulsecore/macro.h>
39 : :
40 : : #include "usergroup.h"
41 : :
42 : : #ifdef HAVE_GRP_H
43 : :
44 : : /* Returns a suitable starting size for a getgrnam_r() or getgrgid_r() buffer,
45 : : plus the size of a struct group.
46 : : */
47 : 2 : static size_t starting_getgr_buflen(void) {
48 : : size_t full_size;
49 : : long n;
50 : : #ifdef _SC_GETGR_R_SIZE_MAX
51 : 2 : n = sysconf(_SC_GETGR_R_SIZE_MAX);
52 : : #else
53 : : n = -1;
54 : : #endif
55 [ - + ]: 2 : if (n <= 0)
56 : 0 : n = 512;
57 : :
58 : 2 : full_size = (size_t) n + sizeof(struct group);
59 : :
60 [ - + ]: 2 : if (full_size < (size_t) n) /* check for integer overflow */
61 : 2 : return (size_t) n;
62 : :
63 : : return full_size;
64 : : }
65 : :
66 : : /* Returns a suitable starting size for a getpwnam_r() or getpwuid_r() buffer,
67 : : plus the size of a struct passwd.
68 : : */
69 : 2 : static size_t starting_getpw_buflen(void) {
70 : : long n;
71 : : size_t full_size;
72 : :
73 : : #ifdef _SC_GETPW_R_SIZE_MAX
74 : 2 : n = sysconf(_SC_GETPW_R_SIZE_MAX);
75 : : #else
76 : : n = -1;
77 : : #endif
78 [ - + ]: 2 : if (n <= 0)
79 : 0 : n = 512;
80 : :
81 : 2 : full_size = (size_t) n + sizeof(struct passwd);
82 : :
83 [ - + ]: 2 : if (full_size < (size_t) n) /* check for integer overflow */
84 : 2 : return (size_t) n;
85 : :
86 : : return full_size;
87 : : }
88 : :
89 : : /* Given a memory allocation (*bufptr) and its length (*buflenptr),
90 : : double the size of the allocation, updating the given buffer and length
91 : : arguments. This function should be used in conjunction with the pa_*alloc
92 : : and pa_xfree functions.
93 : :
94 : : Unlike realloc(), this function does *not* retain the original buffer's
95 : : contents.
96 : :
97 : : Returns 0 on success, nonzero on error. The error cause is indicated by
98 : : errno.
99 : : */
100 : 0 : static int expand_buffer_trashcontents(void **bufptr, size_t *buflenptr) {
101 : : size_t newlen;
102 : :
103 [ # # ][ # # ]: 0 : if (!bufptr || !*bufptr || !buflenptr) {
104 : 0 : errno = EINVAL;
105 : 0 : return -1;
106 : : }
107 : :
108 : 0 : newlen = *buflenptr * 2;
109 : :
110 [ # # ]: 0 : if (newlen < *buflenptr) {
111 : 0 : errno = EOVERFLOW;
112 : 0 : return -1;
113 : : }
114 : :
115 : : /* Don't bother retaining memory contents; free & alloc anew */
116 : 0 : pa_xfree(*bufptr);
117 : :
118 : 0 : *bufptr = pa_xmalloc(newlen);
119 : 0 : *buflenptr = newlen;
120 : :
121 : 0 : return 0;
122 : : }
123 : :
124 : : #ifdef HAVE_GETGRGID_R
125 : : /* Thread-safe getgrgid() replacement.
126 : : Returned value should be freed using pa_getgrgid_free() when the caller is
127 : : finished with the returned group data.
128 : :
129 : : API is the same as getgrgid(), errors are indicated by a NULL return;
130 : : consult errno for the error cause (zero it before calling).
131 : : */
132 : 1 : struct group *pa_getgrgid_malloc(gid_t gid) {
133 : : size_t buflen, getgr_buflen;
134 : : int err;
135 : : void *buf;
136 : : void *getgr_buf;
137 : 1 : struct group *result = NULL;
138 : :
139 : 1 : buflen = starting_getgr_buflen();
140 : 1 : buf = pa_xmalloc(buflen);
141 : :
142 : 1 : getgr_buflen = buflen - sizeof(struct group);
143 : 1 : getgr_buf = (char *)buf + sizeof(struct group);
144 : :
145 [ - + ]: 1 : while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf, getgr_buflen, &result)) == ERANGE) {
146 [ # # ]: 0 : if (expand_buffer_trashcontents(&buf, &buflen))
147 : : break;
148 : :
149 : 0 : getgr_buflen = buflen - sizeof(struct group);
150 : 0 : getgr_buf = (char *)buf + sizeof(struct group);
151 : : }
152 : :
153 [ + - ][ - + ]: 1 : if (err || !result) {
154 : 0 : result = NULL;
155 [ # # ]: 0 : if (buf) {
156 : 0 : pa_xfree(buf);
157 : 0 : buf = NULL;
158 : : }
159 : : }
160 : :
161 [ - + ][ # # ]: 1 : pa_assert(result == buf || result == NULL);
162 : :
163 : 1 : return result;
164 : : }
165 : :
166 : 1 : void pa_getgrgid_free(struct group *grp) {
167 : 1 : pa_xfree(grp);
168 : 1 : }
169 : :
170 : : #else /* !HAVE_GETGRGID_R */
171 : :
172 : : struct group *pa_getgrgid_malloc(gid_t gid) {
173 : : return getgrgid(gid);
174 : : }
175 : :
176 : : void pa_getgrgid_free(struct group *grp) {
177 : : /* nothing */
178 : : return;
179 : : }
180 : :
181 : : #endif /* !HAVE_GETGRGID_R */
182 : :
183 : : #ifdef HAVE_GETGRNAM_R
184 : : /* Thread-safe getgrnam() function.
185 : : Returned value should be freed using pa_getgrnam_free() when the caller is
186 : : finished with the returned group data.
187 : :
188 : : API is the same as getgrnam(), errors are indicated by a NULL return;
189 : : consult errno for the error cause (zero it before calling).
190 : : */
191 : 1 : struct group *pa_getgrnam_malloc(const char *name) {
192 : : size_t buflen, getgr_buflen;
193 : : int err;
194 : : void *buf;
195 : : void *getgr_buf;
196 : 1 : struct group *result = NULL;
197 : :
198 : 1 : buflen = starting_getgr_buflen();
199 : 1 : buf = pa_xmalloc(buflen);
200 : :
201 : 1 : getgr_buflen = buflen - sizeof(struct group);
202 : 1 : getgr_buf = (char *)buf + sizeof(struct group);
203 : :
204 [ - + ]: 1 : while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf, getgr_buflen, &result)) == ERANGE) {
205 [ # # ]: 0 : if (expand_buffer_trashcontents(&buf, &buflen))
206 : : break;
207 : :
208 : 0 : getgr_buflen = buflen - sizeof(struct group);
209 : 0 : getgr_buf = (char *)buf + sizeof(struct group);
210 : : }
211 : :
212 [ + - ][ - + ]: 1 : if (err || !result) {
213 : 0 : result = NULL;
214 [ # # ]: 0 : if (buf) {
215 : 0 : pa_xfree(buf);
216 : 0 : buf = NULL;
217 : : }
218 : : }
219 : :
220 [ - + ][ # # ]: 1 : pa_assert(result == buf || result == NULL);
221 : :
222 : 1 : return result;
223 : : }
224 : :
225 : 1 : void pa_getgrnam_free(struct group *group) {
226 : 1 : pa_xfree(group);
227 : 1 : }
228 : :
229 : : #else /* !HAVE_GETGRNAM_R */
230 : :
231 : : struct group *pa_getgrnam_malloc(const char *name) {
232 : : return getgrnam(name);
233 : : }
234 : :
235 : : void pa_getgrnam_free(struct group *group) {
236 : : /* nothing */
237 : : return;
238 : : }
239 : :
240 : : #endif /* HAVE_GETGRNAM_R */
241 : :
242 : : #endif /* HAVE_GRP_H */
243 : :
244 : : #ifdef HAVE_PWD_H
245 : :
246 : : #ifdef HAVE_GETPWNAM_R
247 : : /* Thread-safe getpwnam() function.
248 : : Returned value should be freed using pa_getpwnam_free() when the caller is
249 : : finished with the returned passwd data.
250 : :
251 : : API is the same as getpwnam(), errors are indicated by a NULL return;
252 : : consult errno for the error cause (zero it before calling).
253 : : */
254 : 1 : struct passwd *pa_getpwnam_malloc(const char *name) {
255 : : size_t buflen, getpw_buflen;
256 : : int err;
257 : : void *buf;
258 : : void *getpw_buf;
259 : 1 : struct passwd *result = NULL;
260 : :
261 : 1 : buflen = starting_getpw_buflen();
262 : 1 : buf = pa_xmalloc(buflen);
263 : :
264 : 1 : getpw_buflen = buflen - sizeof(struct passwd);
265 : 1 : getpw_buf = (char *)buf + sizeof(struct passwd);
266 : :
267 [ - + ]: 1 : while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf, getpw_buflen, &result)) == ERANGE) {
268 [ # # ]: 0 : if (expand_buffer_trashcontents(&buf, &buflen))
269 : : break;
270 : :
271 : 0 : getpw_buflen = buflen - sizeof(struct passwd);
272 : 0 : getpw_buf = (char *)buf + sizeof(struct passwd);
273 : : }
274 : :
275 [ + - ][ - + ]: 1 : if (err || !result) {
276 : 0 : result = NULL;
277 [ # # ]: 0 : if (buf) {
278 : 0 : pa_xfree(buf);
279 : 0 : buf = NULL;
280 : : }
281 : : }
282 : :
283 [ - + ][ # # ]: 1 : pa_assert(result == buf || result == NULL);
284 : :
285 : 1 : return result;
286 : : }
287 : :
288 : 1 : void pa_getpwnam_free(struct passwd *passwd) {
289 : 1 : pa_xfree(passwd);
290 : 1 : }
291 : :
292 : : #else /* !HAVE_GETPWNAM_R */
293 : :
294 : : struct passwd *pa_getpwnam_malloc(const char *name) {
295 : : return getpwnam(name);
296 : : }
297 : :
298 : : void pa_getpwnam_free(struct passwd *passwd) {
299 : : /* nothing */
300 : : return;
301 : : }
302 : :
303 : : #endif /* !HAVE_GETPWNAM_R */
304 : :
305 : : #ifdef HAVE_GETPWUID_R
306 : : /* Thread-safe getpwuid() function.
307 : : Returned value should be freed using pa_getpwuid_free() when the caller is
308 : : finished with the returned group data.
309 : :
310 : : API is the same as getpwuid(), errors are indicated by a NULL return;
311 : : consult errno for the error cause (zero it before calling).
312 : : */
313 : 1 : struct passwd *pa_getpwuid_malloc(uid_t uid) {
314 : : size_t buflen, getpw_buflen;
315 : : int err;
316 : : void *buf;
317 : : void *getpw_buf;
318 : 1 : struct passwd *result = NULL;
319 : :
320 : 1 : buflen = starting_getpw_buflen();
321 : 1 : buf = pa_xmalloc(buflen);
322 : :
323 : 1 : getpw_buflen = buflen - sizeof(struct passwd);
324 : 1 : getpw_buf = (char *)buf + sizeof(struct passwd);
325 : :
326 [ - + ]: 1 : while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf, getpw_buflen, &result)) == ERANGE) {
327 [ # # ]: 0 : if (expand_buffer_trashcontents(&buf, &buflen))
328 : : break;
329 : :
330 : 0 : getpw_buflen = buflen - sizeof(struct passwd);
331 : 0 : getpw_buf = (char *)buf + sizeof(struct passwd);
332 : : }
333 : :
334 [ + - ][ - + ]: 1 : if (err || !result) {
335 : 0 : result = NULL;
336 [ # # ]: 0 : if (buf) {
337 : 0 : pa_xfree(buf);
338 : 0 : buf = NULL;
339 : : }
340 : : }
341 : :
342 [ - + ][ # # ]: 1 : pa_assert(result == buf || result == NULL);
343 : :
344 : 1 : return result;
345 : : }
346 : :
347 : 1 : void pa_getpwuid_free(struct passwd *passwd) {
348 : 1 : pa_xfree(passwd);
349 : 1 : }
350 : :
351 : : #else /* !HAVE_GETPWUID_R */
352 : :
353 : : struct passwd *pa_getpwuid_malloc(uid_t uid) {
354 : : return getpwuid(uid);
355 : : }
356 : :
357 : : void pa_getpwuid_free(struct passwd *passwd) {
358 : : /* nothing */
359 : : return;
360 : : }
361 : :
362 : : #endif /* !HAVE_GETPWUID_R */
363 : :
364 : : #endif /* HAVE_PWD_H */
|