Merge remote branch 'tanuk/fixes'
[pulseaudio-mirror.git] / src / pulsecore / usergroup.c
blob71b13bca88a1950082959995893fb9a05b180639
1 /***
2 This file is part of PulseAudio.
4 Copyright 2009 Ted Percival
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.
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.
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 ***/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <sys/types.h>
27 #include <errno.h>
29 #ifdef HAVE_PWD_H
30 #include <pwd.h>
31 #endif
33 #ifdef HAVE_GRP_H
34 #include <grp.h>
35 #endif
37 #include <pulse/xmalloc.h>
38 #include <pulsecore/macro.h>
40 #include "usergroup.h"
42 #ifdef HAVE_GRP_H
44 /* Returns a suitable starting size for a getgrnam_r() or getgrgid_r() buffer,
45 plus the size of a struct group.
47 static size_t starting_getgr_buflen(void) {
48 size_t full_size;
49 long n;
50 #ifdef _SC_GETGR_R_SIZE_MAX
51 n = sysconf(_SC_GETGR_R_SIZE_MAX);
52 #else
53 n = -1;
54 #endif
55 if (n <= 0)
56 n = 512;
58 full_size = (size_t) n + sizeof(struct group);
60 if (full_size < (size_t) n) /* check for integer overflow */
61 return (size_t) n;
63 return full_size;
66 /* Returns a suitable starting size for a getpwnam_r() or getpwuid_r() buffer,
67 plus the size of a struct passwd.
69 static size_t starting_getpw_buflen(void) {
70 long n;
71 size_t full_size;
73 #ifdef _SC_GETPW_R_SIZE_MAX
74 n = sysconf(_SC_GETPW_R_SIZE_MAX);
75 #else
76 n = -1;
77 #endif
78 if (n <= 0)
79 n = 512;
81 full_size = (size_t) n + sizeof(struct passwd);
83 if (full_size < (size_t) n) /* check for integer overflow */
84 return (size_t) n;
86 return full_size;
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.
94 Unlike realloc(), this function does *not* retain the original buffer's
95 contents.
97 Returns 0 on success, nonzero on error. The error cause is indicated by
98 errno.
100 static int expand_buffer_trashcontents(void **bufptr, size_t *buflenptr) {
101 size_t newlen;
103 if (!bufptr || !*bufptr || !buflenptr) {
104 errno = EINVAL;
105 return -1;
108 newlen = *buflenptr * 2;
110 if (newlen < *buflenptr) {
111 errno = EOVERFLOW;
112 return -1;
115 /* Don't bother retaining memory contents; free & alloc anew */
116 pa_xfree(*bufptr);
118 *bufptr = pa_xmalloc(newlen);
119 *buflenptr = newlen;
121 return 0;
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.
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).
132 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 struct group *result = NULL;
139 buflen = starting_getgr_buflen();
140 buf = pa_xmalloc(buflen);
142 getgr_buflen = buflen - sizeof(struct group);
143 getgr_buf = (char *)buf + sizeof(struct group);
145 while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf,
146 getgr_buflen, &result)) == ERANGE)
148 if (expand_buffer_trashcontents(&buf, &buflen))
149 break;
151 getgr_buflen = buflen - sizeof(struct group);
152 getgr_buf = (char *)buf + sizeof(struct group);
155 if (err || !result) {
156 result = NULL;
157 if (buf) {
158 pa_xfree(buf);
159 buf = NULL;
163 pa_assert(result == buf || result == NULL);
165 return result;
168 void pa_getgrgid_free(struct group *grp) {
169 pa_xfree(grp);
172 #else /* !HAVE_GETGRGID_R */
174 struct group *pa_getgrgid_malloc(gid_t gid) {
175 return getgrgid(gid);
178 void pa_getgrgid_free(struct group *grp) {
179 /* nothing */
180 return;
183 #endif /* !HAVE_GETGRGID_R */
185 #ifdef HAVE_GETGRNAM_R
186 /* Thread-safe getgrnam() function.
187 Returned value should be freed using pa_getgrnam_free() when the caller is
188 finished with the returned group data.
190 API is the same as getgrnam(), errors are indicated by a NULL return;
191 consult errno for the error cause (zero it before calling).
193 struct group *pa_getgrnam_malloc(const char *name) {
194 size_t buflen, getgr_buflen;
195 int err;
196 void *buf;
197 void *getgr_buf;
198 struct group *result = NULL;
200 buflen = starting_getgr_buflen();
201 buf = pa_xmalloc(buflen);
203 getgr_buflen = buflen - sizeof(struct group);
204 getgr_buf = (char *)buf + sizeof(struct group);
206 while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf,
207 getgr_buflen, &result)) == ERANGE)
209 if (expand_buffer_trashcontents(&buf, &buflen))
210 break;
212 getgr_buflen = buflen - sizeof(struct group);
213 getgr_buf = (char *)buf + sizeof(struct group);
216 if (err || !result) {
217 result = NULL;
218 if (buf) {
219 pa_xfree(buf);
220 buf = NULL;
224 pa_assert(result == buf || result == NULL);
226 return result;
229 void pa_getgrnam_free(struct group *group) {
230 pa_xfree(group);
233 #else /* !HAVE_GETGRNAM_R */
235 struct group *pa_getgrnam_malloc(const char *name) {
236 return getgrnam(name);
239 void pa_getgrnam_free(struct group *group) {
240 /* nothing */
241 return;
244 #endif /* HAVE_GETGRNAM_R */
246 #endif /* HAVE_GRP_H */
248 #ifdef HAVE_PWD_H
250 #ifdef HAVE_GETPWNAM_R
251 /* Thread-safe getpwnam() function.
252 Returned value should be freed using pa_getpwnam_free() when the caller is
253 finished with the returned passwd data.
255 API is the same as getpwnam(), errors are indicated by a NULL return;
256 consult errno for the error cause (zero it before calling).
258 struct passwd *pa_getpwnam_malloc(const char *name) {
259 size_t buflen, getpw_buflen;
260 int err;
261 void *buf;
262 void *getpw_buf;
263 struct passwd *result = NULL;
265 buflen = starting_getpw_buflen();
266 buf = pa_xmalloc(buflen);
268 getpw_buflen = buflen - sizeof(struct passwd);
269 getpw_buf = (char *)buf + sizeof(struct passwd);
271 while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf,
272 getpw_buflen, &result)) == ERANGE)
274 if (expand_buffer_trashcontents(&buf, &buflen))
275 break;
277 getpw_buflen = buflen - sizeof(struct passwd);
278 getpw_buf = (char *)buf + sizeof(struct passwd);
281 if (err || !result) {
282 result = NULL;
283 if (buf) {
284 pa_xfree(buf);
285 buf = NULL;
289 pa_assert(result == buf || result == NULL);
291 return result;
294 void pa_getpwnam_free(struct passwd *passwd) {
295 pa_xfree(passwd);
298 #else /* !HAVE_GETPWNAM_R */
300 struct passwd *pa_getpwnam_malloc(const char *name) {
301 return getpwnam(name);
304 void pa_getpwnam_free(struct passwd *passwd) {
305 /* nothing */
306 return;
309 #endif /* !HAVE_GETPWNAM_R */
311 #ifdef HAVE_GETPWUID_R
312 /* Thread-safe getpwuid() function.
313 Returned value should be freed using pa_getpwuid_free() when the caller is
314 finished with the returned group data.
316 API is the same as getpwuid(), errors are indicated by a NULL return;
317 consult errno for the error cause (zero it before calling).
319 struct passwd *pa_getpwuid_malloc(uid_t uid) {
320 size_t buflen, getpw_buflen;
321 int err;
322 void *buf;
323 void *getpw_buf;
324 struct passwd *result = NULL;
326 buflen = starting_getpw_buflen();
327 buf = pa_xmalloc(buflen);
329 getpw_buflen = buflen - sizeof(struct passwd);
330 getpw_buf = (char *)buf + sizeof(struct passwd);
332 while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf,
333 getpw_buflen, &result)) == ERANGE)
335 if (expand_buffer_trashcontents(&buf, &buflen))
336 break;
338 getpw_buflen = buflen - sizeof(struct passwd);
339 getpw_buf = (char *)buf + sizeof(struct passwd);
342 if (err || !result) {
343 result = NULL;
344 if (buf) {
345 pa_xfree(buf);
346 buf = NULL;
350 pa_assert(result == buf || result == NULL);
352 return result;
355 void pa_getpwuid_free(struct passwd *passwd) {
356 pa_xfree(passwd);
359 #else /* !HAVE_GETPWUID_R */
361 struct passwd *pa_getpwuid_malloc(uid_t uid) {
362 return getpwuid(uid);
365 void pa_getpwuid_free(struct passwd *passwd) {
366 /* nothing */
367 return;
370 #endif /* !HAVE_GETPWUID_R */
372 #endif /* HAVE_PWD_H */