]>
git.proxmox.com Git - mirror_lxc.git/blob - src/include/getgrgid_r.c
3 * Copyright © 2018 Christian Brauner <christian.brauner@ubuntu.com>.
4 * Copyright © 2018 Canonical Ltd.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
10 * This program 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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * This function has been copied from musl.
30 #include <sys/socket.h>
34 #define LOGIN_NAME_MAX 256
66 #define INITGRVERSION 0
71 #define FIX(x) (gr->gr_##x = gr->gr_##x - line + buf)
73 static unsigned atou(char **s
)
76 for (x
= 0; **s
- '0' < 10U; ++*s
)
77 x
= 10 * x
+ (**s
- '0');
81 static int __getgrent_a(FILE *f
, struct group
*gr
, char **line
, size_t *size
,
82 char ***mem
, size_t *nmem
, struct group
**res
)
89 #ifdef HAVE_PTHREAD_SETCANCELSTATE
92 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
96 if ((l
= getline(line
, size
, f
)) < 0) {
97 rv
= ferror(f
) ? errno
: 0;
107 if (!(s
= strchr(s
, ':')))
112 if (!(s
= strchr(s
, ':')))
116 gr
->gr_gid
= atou(&s
);
125 for (*nmem
= !!*s
; *s
; s
++)
129 *mem
= calloc(sizeof(char *), *nmem
+ 1);
139 for (s
= mems
, i
= 0; *s
; s
++)
141 *s
++ = 0, mem
[0][++i
] = s
;
149 #ifdef HAVE_PTHREAD_SETCANCELSTATE
150 pthread_setcancelstate(cs
, 0);
159 static char *itoa(char *p
, uint32_t x
)
161 // number of digits in a uint32_t + NUL
171 static const struct {
174 } addr
= {AF_UNIX
, "/var/run/nscd/socket"};
176 static FILE *__nscd_query(int32_t req
, const char *key
, int32_t *buf
,
177 size_t len
, int *swap
)
182 int32_t req_buf
[REQ_LEN
] = {NSCDVERSION
, req
,
183 strnlen(key
, LOGIN_NAME_MAX
) + 1};
184 struct msghdr msg
= {.msg_iov
=
185 (struct iovec
[]){{&req_buf
, sizeof(req_buf
)},
186 {(char *)key
, strlen(key
) + 1}},
188 int errno_save
= errno
;
193 buf
[0] = NSCDVERSION
;
195 fd
= socket(PF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
, 0);
199 if (!(f
= fdopen(fd
, "r"))) {
204 if (req_buf
[2] > LOGIN_NAME_MAX
)
207 if (connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
208 /* If there isn't a running nscd we simulate a "not found"
209 * result and the caller is responsible for calling
210 * fclose on the (unconnected) socket. The value of
211 * errno must be left unchanged in this case. */
212 if (errno
== EACCES
|| errno
== ECONNREFUSED
|| errno
== ENOENT
) {
219 if (sendmsg(fd
, &msg
, MSG_NOSIGNAL
) < 0)
222 if (!fread(buf
, len
, 1, f
)) {
223 /* If the VERSION entry mismatches nscd will disconnect. The
224 * most likely cause is that the endianness mismatched. So, we
225 * byteswap and try once more. (if we already swapped, just
232 for (i
= 0; i
< sizeof(req_buf
) / sizeof(req_buf
[0]);
234 req_buf
[i
] = bswap_32(req_buf
[i
]);
245 for (i
= 0; i
< len
/ sizeof(buf
[0]); i
++) {
246 buf
[i
] = bswap_32(buf
[i
]);
250 /* The first entry in every nscd response is the version number. This
251 * really shouldn't happen, and is evidence of some form of malformed
254 if (buf
[0] != NSCDVERSION
) {
265 static int __getgr_a(const char *name
, gid_t gid
, struct group
*gr
, char **buf
,
266 size_t *size
, char ***mem
, size_t *nmem
, struct group
**res
)
270 #ifdef HAVE_PTHREAD_SETCANCELSTATE
273 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
278 f
= fopen("/etc/group", "rbe");
284 while (!(rv
= __getgrent_a(f
, gr
, buf
, size
, mem
, nmem
, res
)) && *res
) {
285 if ((name
&& !strcmp(name
, (*res
)->gr_name
)) ||
286 (!name
&& (*res
)->gr_gid
== gid
)) {
292 if (!*res
&& (rv
== 0 || rv
== ENOENT
|| rv
== ENOTDIR
)) {
293 int32_t req
= name
? GETGRBYNAME
: GETGRBYGID
;
296 int32_t groupbuf
[GR_LEN
] = {0};
298 size_t grlist_len
= 0;
299 char gidbuf
[11] = {0};
306 if (gid
< 0 || gid
> UINT32_MAX
) {
310 key
= itoa(gidbuf
, gid
);
313 f
= __nscd_query(req
, key
, groupbuf
, sizeof groupbuf
, &swap
);
319 if (!groupbuf
[GRFOUND
]) {
324 if (!groupbuf
[GRNAMELEN
] || !groupbuf
[GRPASSWDLEN
]) {
329 if ((int64_t)groupbuf
[GRNAMELEN
] >
330 (int64_t)(SIZE_MAX
- groupbuf
[GRPASSWDLEN
])) {
334 len
= groupbuf
[GRNAMELEN
] + groupbuf
[GRPASSWDLEN
];
336 for (i
= 0; i
< groupbuf
[GRMEMCNT
]; i
++) {
338 if (fread(&name_len
, sizeof name_len
, 1, f
) < 1) {
339 rv
= ferror(f
) ? errno
: EIO
;
343 name_len
= bswap_32(name_len
);
345 if (name_len
> SIZE_MAX
- grlist_len
||
346 name_len
> SIZE_MAX
- len
) {
351 grlist_len
+= name_len
;
354 if (len
> *size
|| !*buf
) {
355 char *tmp
= realloc(*buf
, len
);
364 if (!fread(*buf
, len
, 1, f
)) {
365 rv
= ferror(f
) ? errno
: EIO
;
369 if (((size_t)(groupbuf
[GRMEMCNT
] + 1)) > *nmem
) {
370 if (((size_t)(groupbuf
[GRMEMCNT
] + 1)) >
371 (SIZE_MAX
/ sizeof(char *))) {
375 char **tmp
= realloc(*mem
, (groupbuf
[GRMEMCNT
] + 1) *
382 *nmem
= groupbuf
[GRMEMCNT
] + 1;
385 if (groupbuf
[GRMEMCNT
]) {
387 *buf
+ groupbuf
[GRNAMELEN
] + groupbuf
[GRPASSWDLEN
];
388 for (ptr
= mem
[0][0], i
= 0;
389 ptr
!= mem
[0][0] + grlist_len
; ptr
++)
391 mem
[0][++i
] = ptr
+ 1;
394 if (i
!= groupbuf
[GRMEMCNT
]) {
403 gr
->gr_passwd
= gr
->gr_name
+ groupbuf
[GRNAMELEN
];
404 gr
->gr_gid
= groupbuf
[GRGID
];
407 if (gr
->gr_passwd
[-1] ||
408 gr
->gr_passwd
[groupbuf
[GRPASSWDLEN
] - 1]) {
413 if ((name
&& strcmp(name
, gr
->gr_name
)) ||
414 (!name
&& gid
!= gr
->gr_gid
)) {
428 #ifdef HAVE_PTHREAD_SETCANCELSTATE
429 pthread_setcancelstate(cs
, 0);
437 static int getgr_r(const char *name
, gid_t gid
, struct group
*gr
, char *buf
,
438 size_t size
, struct group
**res
)
447 #ifdef HAVE_PTHREAD_SETCANCELSTATE
450 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
453 rv
= __getgr_a(name
, gid
, gr
, &line
, &len
, &mem
, &nmem
, res
);
454 if (*res
&& size
< len
+ (nmem
+ 1) * sizeof(char *) + 32) {
459 buf
+= (16 - (uintptr_t)buf
) % 16;
460 gr
->gr_mem
= (void *)buf
;
461 buf
+= (nmem
+ 1) * sizeof(char *);
462 memcpy(buf
, line
, len
);
465 for (i
= 0; mem
[i
]; i
++)
466 gr
->gr_mem
[i
] = mem
[i
] - line
+ buf
;
472 #ifdef HAVE_PTHREAD_SETCANCELSTATE
473 pthread_setcancelstate(cs
, 0);
481 int getgrgid_r(gid_t gid
, struct group
*gr
, char *buf
, size_t size
, struct group
**res
)
483 return getgr_r(0, gid
, gr
, buf
, size
, res
);