2 * Copyright (c) 2013 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
45 #include "libcapsicum.h"
46 #include "libcapsicum_grp.h"
48 static struct group ggrp;
50 static size_t gbufsize;
63 gbuffer = realloc(buf, gbufsize);
64 if (gbuffer == NULL) {
69 memset(gbuffer, 0, gbufsize);
75 group_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
76 char **bufferp, size_t *bufsizep)
81 str = nvlist_get_string(nvl, fieldname);
82 len = strlcpy(*bufferp, str, *bufsizep);
93 group_unpack_members(const nvlist_t *nvl, char ***fieldp, char **bufferp,
98 size_t nmem, datasize, strsize;
101 if (!nvlist_exists_number(nvl, "gr_nmem")) {
102 datasize = _ALIGNBYTES + sizeof(char *);
103 if (datasize >= *bufsizep)
105 outstrs = (char **)_ALIGN(*bufferp);
108 *bufferp += datasize;
109 *bufsizep -= datasize;
113 nmem = (size_t)nvlist_get_number(nvl, "gr_nmem");
114 datasize = _ALIGNBYTES + sizeof(char *) * (nmem + 1);
115 for (ii = 0; ii < nmem; ii++) {
116 mem = dnvlist_getf_string(nvl, NULL, "gr_mem[%u]", ii);
119 datasize += strlen(mem) + 1;
122 if (datasize >= *bufsizep)
125 outstrs = (char **)_ALIGN(*bufferp);
126 str = (char *)outstrs + sizeof(char *) * (nmem + 1);
127 for (ii = 0; ii < nmem; ii++) {
128 mem = nvlist_getf_string(nvl, "gr_mem[%u]", ii);
129 strsize = strlen(mem) + 1;
130 memcpy(str, mem, strsize);
138 *bufferp += datasize;
139 *bufsizep -= datasize;
145 group_unpack(const nvlist_t *nvl, struct group *grp, char *buffer,
150 if (!nvlist_exists_string(nvl, "gr_name"))
153 memset(grp, 0, sizeof(*grp));
155 error = group_unpack_string(nvl, "gr_name", &grp->gr_name, &buffer,
159 error = group_unpack_string(nvl, "gr_passwd", &grp->gr_passwd, &buffer,
163 grp->gr_gid = (gid_t)nvlist_get_number(nvl, "gr_gid");
164 error = group_unpack_members(nvl, &grp->gr_mem, &buffer, &bufsize);
172 cap_getgrcommon_r(cap_channel_t *chan, const char *cmd, const char *name,
173 gid_t gid, struct group *grp, char *buffer, size_t bufsize,
174 struct group **result)
180 nvl = nvlist_create(0);
181 nvlist_add_string(nvl, "cmd", cmd);
182 if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0) {
184 } else if (strcmp(cmd, "getgrnam") == 0 ||
185 strcmp(cmd, "getgrnam_r") == 0) {
186 nvlist_add_string(nvl, "name", name);
187 } else if (strcmp(cmd, "getgrgid") == 0 ||
188 strcmp(cmd, "getgrgid_r") == 0) {
189 nvlist_add_number(nvl, "gid", (uint64_t)gid);
193 nvl = cap_xfer_nvlist(chan, nvl);
199 error = (int)nvlist_get_number(nvl, "error");
206 if (!nvlist_exists_string(nvl, "gr_name")) {
213 getgr_r = (strcmp(cmd, "getgrent_r") == 0 ||
214 strcmp(cmd, "getgrnam_r") == 0 || strcmp(cmd, "getgrgid_r") == 0);
217 error = group_unpack(nvl, grp, buffer, bufsize);
218 if (getgr_r || error != ERANGE)
220 assert(buffer == gbuffer);
221 assert(bufsize == gbufsize);
222 error = group_resize();
225 /* Update pointers after resize. */
240 static struct group *
241 cap_getgrcommon(cap_channel_t *chan, const char *cmd, const char *name,
244 struct group *result;
249 error = cap_getgrcommon_r(chan, cmd, name, gid, &ggrp, gbuffer,
262 cap_getgrent(cap_channel_t *chan)
265 return (cap_getgrcommon(chan, "getgrent", NULL, 0));
269 cap_getgrnam(cap_channel_t *chan, const char *name)
272 return (cap_getgrcommon(chan, "getgrnam", name, 0));
276 cap_getgrgid(cap_channel_t *chan, gid_t gid)
279 return (cap_getgrcommon(chan, "getgrgid", NULL, gid));
283 cap_getgrent_r(cap_channel_t *chan, struct group *grp, char *buffer,
284 size_t bufsize, struct group **result)
287 return (cap_getgrcommon_r(chan, "getgrent_r", NULL, 0, grp, buffer,
292 cap_getgrnam_r(cap_channel_t *chan, const char *name, struct group *grp,
293 char *buffer, size_t bufsize, struct group **result)
296 return (cap_getgrcommon_r(chan, "getgrnam_r", name, 0, grp, buffer,
301 cap_getgrgid_r(cap_channel_t *chan, gid_t gid, struct group *grp, char *buffer,
302 size_t bufsize, struct group **result)
305 return (cap_getgrcommon_r(chan, "getgrgid_r", NULL, gid, grp, buffer,
310 cap_setgroupent(cap_channel_t *chan, int stayopen)
314 nvl = nvlist_create(0);
315 nvlist_add_string(nvl, "cmd", "setgroupent");
316 nvlist_add_bool(nvl, "stayopen", stayopen != 0);
317 nvl = cap_xfer_nvlist(chan, nvl);
320 if (nvlist_get_number(nvl, "error") != 0) {
321 errno = nvlist_get_number(nvl, "error");
331 cap_setgrent(cap_channel_t *chan)
335 nvl = nvlist_create(0);
336 nvlist_add_string(nvl, "cmd", "setgrent");
337 nvl = cap_xfer_nvlist(chan, nvl);
340 if (nvlist_get_number(nvl, "error") != 0) {
341 errno = nvlist_get_number(nvl, "error");
351 cap_endgrent(cap_channel_t *chan)
355 nvl = nvlist_create(0);
356 nvlist_add_string(nvl, "cmd", "endgrent");
357 /* Ignore any errors, we have no way to report them. */
358 nvlist_destroy(cap_xfer_nvlist(chan, nvl));
362 cap_grp_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
364 nvlist_t *limits, *nvl;
367 if (cap_limit_get(chan, &limits) < 0)
369 if (limits == NULL) {
370 limits = nvlist_create(0);
372 if (nvlist_exists_nvlist(limits, "cmds"))
373 nvlist_free_nvlist(limits, "cmds");
375 nvl = nvlist_create(0);
376 for (i = 0; i < ncmds; i++)
377 nvlist_add_null(nvl, cmds[i]);
378 nvlist_move_nvlist(limits, "cmds", nvl);
379 return (cap_limit_set(chan, limits));
383 cap_grp_limit_fields(cap_channel_t *chan, const char * const *fields,
386 nvlist_t *limits, *nvl;
389 if (cap_limit_get(chan, &limits) < 0)
391 if (limits == NULL) {
392 limits = nvlist_create(0);
394 if (nvlist_exists_nvlist(limits, "fields"))
395 nvlist_free_nvlist(limits, "fields");
397 nvl = nvlist_create(0);
398 for (i = 0; i < nfields; i++)
399 nvlist_add_null(nvl, fields[i]);
400 nvlist_move_nvlist(limits, "fields", nvl);
401 return (cap_limit_set(chan, limits));
405 cap_grp_limit_groups(cap_channel_t *chan, const char * const *names,
406 size_t nnames, gid_t *gids, size_t ngids)
408 nvlist_t *limits, *groups;
411 if (cap_limit_get(chan, &limits) < 0)
413 if (limits == NULL) {
414 limits = nvlist_create(0);
416 if (nvlist_exists_nvlist(limits, "groups"))
417 nvlist_free_nvlist(limits, "groups");
419 groups = nvlist_create(0);
420 for (i = 0; i < ngids; i++)
421 nvlist_addf_number(groups, (uint64_t)gids[i], "gid%u", i);
422 for (i = 0; i < nnames; i++)
423 nvlist_addf_string(groups, names[i], "name%u", i);
424 nvlist_move_nvlist(limits, "groups", groups);
425 return (cap_limit_set(chan, limits));