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