Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio
[platform/upstream/pulseaudio.git] / src / pulsecore / usergroup.c
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 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;
57
58     full_size = (size_t) n + sizeof(struct group);
59
60     if (full_size < (size_t) n) /* check for integer overflow */
61         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 static size_t starting_getpw_buflen(void) {
70     long n;
71     size_t full_size;
72
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;
80
81     full_size = (size_t) n + sizeof(struct passwd);
82
83     if (full_size < (size_t) n) /* check for integer overflow */
84         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 static int expand_buffer_trashcontents(void **bufptr, size_t *buflenptr) {
101     size_t newlen;
102
103     if (!bufptr || !*bufptr || !buflenptr) {
104         errno = EINVAL;
105         return -1;
106     }
107
108     newlen = *buflenptr * 2;
109
110     if (newlen < *buflenptr) {
111         errno = EOVERFLOW;
112         return -1;
113     }
114
115     /* Don't bother retaining memory contents; free & alloc anew */
116     pa_xfree(*bufptr);
117
118     *bufptr = pa_xmalloc(newlen);
119     *buflenptr = newlen;
120
121     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 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;
138
139     buflen = starting_getgr_buflen();
140     buf = pa_xmalloc(buflen);
141
142     getgr_buflen = buflen - sizeof(struct group);
143     getgr_buf = (char *)buf + sizeof(struct group);
144
145     while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf,
146                     getgr_buflen, &result)) == ERANGE)
147     {
148         if (expand_buffer_trashcontents(&buf, &buflen))
149             break;
150
151         getgr_buflen = buflen - sizeof(struct group);
152         getgr_buf = (char *)buf + sizeof(struct group);
153     }
154
155     if (err || !result) {
156         result = NULL;
157         if (buf) {
158             pa_xfree(buf);
159             buf = NULL;
160         }
161     }
162
163     pa_assert(result == buf || result == NULL);
164
165     return result;
166 }
167
168 void pa_getgrgid_free(struct group *grp) {
169     pa_xfree(grp);
170 }
171
172 #else /* !HAVE_GETGRGID_R */
173
174 struct group *pa_getgrgid_malloc(gid_t gid) {
175     return getgrgid(gid);
176 }
177
178 void pa_getgrgid_free(struct group *grp) {
179     /* nothing */
180     return;
181 }
182
183 #endif /* !HAVE_GETGRGID_R */
184
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.
189
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).
192  */
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;
199
200     buflen = starting_getgr_buflen();
201     buf = pa_xmalloc(buflen);
202
203     getgr_buflen = buflen - sizeof(struct group);
204     getgr_buf = (char *)buf + sizeof(struct group);
205
206     while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf,
207                     getgr_buflen, &result)) == ERANGE)
208     {
209         if (expand_buffer_trashcontents(&buf, &buflen))
210             break;
211
212         getgr_buflen = buflen - sizeof(struct group);
213         getgr_buf = (char *)buf + sizeof(struct group);
214     }
215
216     if (err || !result) {
217         result = NULL;
218         if (buf) {
219             pa_xfree(buf);
220             buf = NULL;
221         }
222     }
223
224     pa_assert(result == buf || result == NULL);
225
226     return result;
227 }
228
229 void pa_getgrnam_free(struct group *group) {
230     pa_xfree(group);
231 }
232
233 #else /* !HAVE_GETGRNAM_R */
234
235 struct group *pa_getgrnam_malloc(const char *name) {
236     return getgrnam(name);
237 }
238
239 void pa_getgrnam_free(struct group *group) {
240     /* nothing */
241     return;
242 }
243
244 #endif /* HAVE_GETGRNAM_R */
245
246 #endif /* HAVE_GRP_H */
247
248 #ifdef HAVE_PWD_H
249
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.
254
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).
257  */
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;
264
265     buflen = starting_getpw_buflen();
266     buf = pa_xmalloc(buflen);
267
268     getpw_buflen = buflen - sizeof(struct passwd);
269     getpw_buf = (char *)buf + sizeof(struct passwd);
270
271     while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf,
272                     getpw_buflen, &result)) == ERANGE)
273     {
274         if (expand_buffer_trashcontents(&buf, &buflen))
275             break;
276
277         getpw_buflen = buflen - sizeof(struct passwd);
278         getpw_buf = (char *)buf + sizeof(struct passwd);
279     }
280
281     if (err || !result) {
282         result = NULL;
283         if (buf) {
284             pa_xfree(buf);
285             buf = NULL;
286         }
287     }
288
289     pa_assert(result == buf || result == NULL);
290
291     return result;
292 }
293
294 void pa_getpwnam_free(struct passwd *passwd) {
295     pa_xfree(passwd);
296 }
297
298 #else /* !HAVE_GETPWNAM_R */
299
300 struct passwd *pa_getpwnam_malloc(const char *name) {
301     return getpwnam(name);
302 }
303
304 void pa_getpwnam_free(struct passwd *passwd) {
305     /* nothing */
306     return;
307 }
308
309 #endif /* !HAVE_GETPWNAM_R */
310
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.
315
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).
318  */
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;
325
326     buflen = starting_getpw_buflen();
327     buf = pa_xmalloc(buflen);
328
329     getpw_buflen = buflen - sizeof(struct passwd);
330     getpw_buf = (char *)buf + sizeof(struct passwd);
331
332     while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf,
333                     getpw_buflen, &result)) == ERANGE)
334     {
335         if (expand_buffer_trashcontents(&buf, &buflen))
336             break;
337
338         getpw_buflen = buflen - sizeof(struct passwd);
339         getpw_buf = (char *)buf + sizeof(struct passwd);
340     }
341
342     if (err || !result) {
343         result = NULL;
344         if (buf) {
345             pa_xfree(buf);
346             buf = NULL;
347         }
348     }
349
350     pa_assert(result == buf || result == NULL);
351
352     return result;
353 }
354
355 void pa_getpwuid_free(struct passwd *passwd) {
356     pa_xfree(passwd);
357 }
358
359 #else /* !HAVE_GETPWUID_R */
360
361 struct passwd *pa_getpwuid_malloc(uid_t uid) {
362     return getpwuid(uid);
363 }
364
365 void pa_getpwuid_free(struct passwd *passwd) {
366     /* nothing */
367     return;
368 }
369
370 #endif /* !HAVE_GETPWUID_R */
371
372 #endif /* HAVE_PWD_H */