Index: head/lib/libcasper/services/cap_grp/cap_grp.3 =================================================================== --- head/lib/libcasper/services/cap_grp/cap_grp.3 (revision 331145) +++ head/lib/libcasper/services/cap_grp/cap_grp.3 (revision 331146) @@ -1,228 +1,228 @@ .\" Copyright (c) 2018 Mariusz Zaborski .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd February 26, 2018 +.Dd March 18, 2018 .Dt CAP_GRP 3 .Os .Sh NAME .Nm cap_getgrent , .Nm cap_getgrnam , .Nm cap_getgrgid , .Nm cap_getgrent_r , .Nm cap_getgrnam_r , .Nm cap_getgrgid_r , .Nm cap_setgroupent , .Nm cap_setgrent , .Nm cap_endgrent , .Nm cap_grp_limit_cmds , .Nm cap_grp_limit_fields , .Nm cap_grp_limit_groups .Nd "library for group database operations in capability mode" .Sh LIBRARY .Lb libcap_grp .Sh SYNOPSIS .In sys/nv.h .In libcasper.h .In casper/cap_grp.h .Ft "struct group *" .Fn cap_getgrent "cap_channel_t *chan" .Ft "struct group *" .Fn cap_getgrnam "cap_channel_t *chan" "const char *name" .Ft "struct group *" .Fn cap_getgrgid "cap_channel_t *chan" "gid_t gid" .Ft "int" .Fn cap_getgrent_r "cap_channel_t *chan" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result" .Ft "int" .Fn cap_getgrnam_r "cap_channel_t *chan" "const char *name" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result" .Ft int .Fn cap_getgrgid_r "cap_channel_t *chan" "gid_t gid" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result" .Ft int .Fn cap_setgroupent "cap_channel_t *chan" "int stayopen" .Ft int .Fn cap_setgrent "cap_channel_t *chan" .Ft void .Fn cap_endgrent "cap_channel_t *chan" .Ft int .Fn cap_grp_limit_cmds "cap_channel_t *chan" "const char * const *cmds" "size_t ncmds" .Ft int .Fn cap_grp_limit_fields "cap_channel_t *chan" "const char * const *fields" "size_t nfields" .Ft int -.Fn cap_grp_limit_groups "cap_channel_t *chan" "const char * const *names" "size_t nnames" "gid_t *gids" "size_t ngids" +.Fn cap_grp_limit_groups "cap_channel_t *chan" "const char * const *names" "size_t nnames" "const gid_t *gids" "size_t ngids" .Sh DESCRIPTION The functions .Fn cap_getgrent , .Fn cap_getgrnam , .Fn cap_getgrgid , .Fn cap_getgrent_r , .Fn cap_getgrnam_r , .Fn cap_getgrgid_r , .Fn cap_setgroupent , .Fn cap_setgrent , and .Fn cap_endgrent are respectively equivalent to .Xr getgrent 3 , .Xr getgrnam 3 , .Xr getgrgid 3 , .Xr getgrent_r 3 , .Xr getgrnam_r 3 , .Xr getgrgid_r 3 , .Xr setgroupent 3 , .Xr setgrent 3 , and .Xr endgrent 3 except that the connection to the .Nm system.grp service needs to be provided. .Pp The .Fn cap_grp_limit_cmds function limits the functions allowed in the service. The .Fa cmds variable can be set to .Dv getgrent , .Dv getgrnam , .Dv getgrgid , .Dv getgrent_r , .Dv getgrnam_r , .Dv getgrgid_r , .Dv setgroupent , .Dv setgrent , or .Dv endgrent which will allow to use the function associated with the name. The .Fa ncmds variable contains the number of .Fa cmds provided. .Pp The .Fn cap_grp_limit_fields function allows limit fields returned in the structure .Vt group . The .Fa fields variable can be set to .Dv gr_name .Dv gr_passwd .Dv gr_gid or .Dv gr_mem . The field which was set as the limit will be returned, while the rest of the values not set this way will have default values. The .Fa nfields variable contains the number of .Fa fields provided. .Pp The .Fn cap_grp_limit_groups function allows to limit access to groups. The .Fa names variable allows to limit groups by name and the .Fa gids variable by the group number. The .Fa nnames and .Fa ngids variables provide numbers of limited names and gids. .Sh EXAMPLES The following example first opens a capability to casper and then uses this capability to create the .Nm system.grp casper service and uses it to get a group name. .Bd -literal cap_channel_t *capcas, *capgrp; const char *cmds[] = { "getgrgid" }; const char *fields[] = { "gr_name" }; -gid_t gid[] = { 1 }; +const gid_t gid[] = { 1 }; struct group *group; /* Open capability to Casper. */ capcas = cap_init(); if (capcas == NULL) err(1, "Unable to contact Casper"); /* Enter capability mode sandbox. */ if (cap_enter() < 0 && errno != ENOSYS) err(1, "Unable to enter capability mode"); /* Use Casper capability to create capability to the system.grp service. */ capgrp = cap_service_open(capcas, "system.grp"); if (capgrp == NULL) err(1, "Unable to open system.grp service"); /* Close Casper capability, we don't need it anymore. */ cap_close(capcas); /* Limit service to one single function. */ if (cap_grp_limit_cmds(capgrp, cmds, nitems(cmds))) err(1, "Unable to limit access to system.grp service"); /* Limit service to one field as we only need name of the group. */ if (cap_grp_limit_fields(capgrp, fields, nitems(fields))) err(1, "Unable to limit access to system.grp service"); /* Limit service to one gid. */ if (cap_grp_limit_groups(capgrp, NULL, 0, gid, nitems(gid))) err(1, "Unable to limit access to system.grp service"); group = cap_getgrgid(capgrp, gid[0]); if (group == NULL) err(1, "Unable to get name of group"); printf("GID %d is associated with name %s.\\n", gid[0], group->gr_name); cap_close(capgrp); .Ed .Sh SEE ALSO .Xr cap_enter 2 , .Xr endgrent 3 , .Xr err 3 , .Xr getgrent 3 , .Xr getgrent_r 3 , .Xr getgrgid 3 , .Xr getgrgid_r 3 , .Xr getgrnam 3 , .Xr getgrnam_r 3 , .Xr setgrent 3 , .Xr setgroupent 3 , .Xr capsicum 4 , .Xr nv 9 .Sh AUTHORS The .Nm cap_grp service was implemented by .An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net under sponsorship from the FreeBSD Foundation. .Pp This manual page was written by .An Mariusz Zaborski Aq Mt oshogbo@FreeBSD.org . Index: head/lib/libcasper/services/cap_grp/cap_grp.c =================================================================== --- head/lib/libcasper/services/cap_grp/cap_grp.c (revision 331145) +++ head/lib/libcasper/services/cap_grp/cap_grp.c (revision 331146) @@ -1,791 +1,791 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 The FreeBSD Foundation * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "cap_grp.h" static struct group ggrp; static char *gbuffer; static size_t gbufsize; static int group_resize(void) { char *buf; if (gbufsize == 0) gbufsize = 1024; else gbufsize *= 2; buf = gbuffer; gbuffer = realloc(buf, gbufsize); if (gbuffer == NULL) { free(buf); gbufsize = 0; return (ENOMEM); } memset(gbuffer, 0, gbufsize); return (0); } static int group_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp, char **bufferp, size_t *bufsizep) { const char *str; size_t len; str = nvlist_get_string(nvl, fieldname); len = strlcpy(*bufferp, str, *bufsizep); if (len >= *bufsizep) return (ERANGE); *fieldp = *bufferp; *bufferp += len + 1; *bufsizep -= len + 1; return (0); } static int group_unpack_members(const nvlist_t *nvl, char ***fieldp, char **bufferp, size_t *bufsizep) { const char *mem; char **outstrs, *str, nvlname[64]; size_t nmem, datasize, strsize; unsigned int ii; int n; if (!nvlist_exists_number(nvl, "gr_nmem")) { datasize = _ALIGNBYTES + sizeof(char *); if (datasize >= *bufsizep) return (ERANGE); outstrs = (char **)_ALIGN(*bufferp); outstrs[0] = NULL; *fieldp = outstrs; *bufferp += datasize; *bufsizep -= datasize; return (0); } nmem = (size_t)nvlist_get_number(nvl, "gr_nmem"); datasize = _ALIGNBYTES + sizeof(char *) * (nmem + 1); for (ii = 0; ii < nmem; ii++) { n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii); assert(n > 0 && n < (int)sizeof(nvlname)); mem = dnvlist_get_string(nvl, nvlname, NULL); if (mem == NULL) return (EINVAL); datasize += strlen(mem) + 1; } if (datasize >= *bufsizep) return (ERANGE); outstrs = (char **)_ALIGN(*bufferp); str = (char *)outstrs + sizeof(char *) * (nmem + 1); for (ii = 0; ii < nmem; ii++) { n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii); assert(n > 0 && n < (int)sizeof(nvlname)); mem = nvlist_get_string(nvl, nvlname); strsize = strlen(mem) + 1; memcpy(str, mem, strsize); outstrs[ii] = str; str += strsize; } assert(ii == nmem); outstrs[ii] = NULL; *fieldp = outstrs; *bufferp += datasize; *bufsizep -= datasize; return (0); } static int group_unpack(const nvlist_t *nvl, struct group *grp, char *buffer, size_t bufsize) { int error; if (!nvlist_exists_string(nvl, "gr_name")) return (EINVAL); memset(grp, 0, sizeof(*grp)); error = group_unpack_string(nvl, "gr_name", &grp->gr_name, &buffer, &bufsize); if (error != 0) return (error); error = group_unpack_string(nvl, "gr_passwd", &grp->gr_passwd, &buffer, &bufsize); if (error != 0) return (error); grp->gr_gid = (gid_t)nvlist_get_number(nvl, "gr_gid"); error = group_unpack_members(nvl, &grp->gr_mem, &buffer, &bufsize); if (error != 0) return (error); return (0); } static int cap_getgrcommon_r(cap_channel_t *chan, const char *cmd, const char *name, gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result) { nvlist_t *nvl; bool getgr_r; int error; nvl = nvlist_create(0); nvlist_add_string(nvl, "cmd", cmd); if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0) { /* Add nothing. */ } else if (strcmp(cmd, "getgrnam") == 0 || strcmp(cmd, "getgrnam_r") == 0) { nvlist_add_string(nvl, "name", name); } else if (strcmp(cmd, "getgrgid") == 0 || strcmp(cmd, "getgrgid_r") == 0) { nvlist_add_number(nvl, "gid", (uint64_t)gid); } else { abort(); } nvl = cap_xfer_nvlist(chan, nvl); if (nvl == NULL) { assert(errno != 0); *result = NULL; return (errno); } error = (int)nvlist_get_number(nvl, "error"); if (error != 0) { nvlist_destroy(nvl); *result = NULL; return (error); } if (!nvlist_exists_string(nvl, "gr_name")) { /* Not found. */ nvlist_destroy(nvl); *result = NULL; return (0); } getgr_r = (strcmp(cmd, "getgrent_r") == 0 || strcmp(cmd, "getgrnam_r") == 0 || strcmp(cmd, "getgrgid_r") == 0); for (;;) { error = group_unpack(nvl, grp, buffer, bufsize); if (getgr_r || error != ERANGE) break; assert(buffer == gbuffer); assert(bufsize == gbufsize); error = group_resize(); if (error != 0) break; /* Update pointers after resize. */ buffer = gbuffer; bufsize = gbufsize; } nvlist_destroy(nvl); if (error == 0) *result = grp; else *result = NULL; return (error); } static struct group * cap_getgrcommon(cap_channel_t *chan, const char *cmd, const char *name, gid_t gid) { struct group *result; int error, serrno; serrno = errno; error = cap_getgrcommon_r(chan, cmd, name, gid, &ggrp, gbuffer, gbufsize, &result); if (error != 0) { errno = error; return (NULL); } errno = serrno; return (result); } struct group * cap_getgrent(cap_channel_t *chan) { return (cap_getgrcommon(chan, "getgrent", NULL, 0)); } struct group * cap_getgrnam(cap_channel_t *chan, const char *name) { return (cap_getgrcommon(chan, "getgrnam", name, 0)); } struct group * cap_getgrgid(cap_channel_t *chan, gid_t gid) { return (cap_getgrcommon(chan, "getgrgid", NULL, gid)); } int cap_getgrent_r(cap_channel_t *chan, struct group *grp, char *buffer, size_t bufsize, struct group **result) { return (cap_getgrcommon_r(chan, "getgrent_r", NULL, 0, grp, buffer, bufsize, result)); } int cap_getgrnam_r(cap_channel_t *chan, const char *name, struct group *grp, char *buffer, size_t bufsize, struct group **result) { return (cap_getgrcommon_r(chan, "getgrnam_r", name, 0, grp, buffer, bufsize, result)); } int cap_getgrgid_r(cap_channel_t *chan, gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result) { return (cap_getgrcommon_r(chan, "getgrgid_r", NULL, gid, grp, buffer, bufsize, result)); } int cap_setgroupent(cap_channel_t *chan, int stayopen) { nvlist_t *nvl; nvl = nvlist_create(0); nvlist_add_string(nvl, "cmd", "setgroupent"); nvlist_add_bool(nvl, "stayopen", stayopen != 0); nvl = cap_xfer_nvlist(chan, nvl); if (nvl == NULL) return (0); if (nvlist_get_number(nvl, "error") != 0) { errno = nvlist_get_number(nvl, "error"); nvlist_destroy(nvl); return (0); } nvlist_destroy(nvl); return (1); } int cap_setgrent(cap_channel_t *chan) { nvlist_t *nvl; nvl = nvlist_create(0); nvlist_add_string(nvl, "cmd", "setgrent"); nvl = cap_xfer_nvlist(chan, nvl); if (nvl == NULL) return (0); if (nvlist_get_number(nvl, "error") != 0) { errno = nvlist_get_number(nvl, "error"); nvlist_destroy(nvl); return (0); } nvlist_destroy(nvl); return (1); } void cap_endgrent(cap_channel_t *chan) { nvlist_t *nvl; nvl = nvlist_create(0); nvlist_add_string(nvl, "cmd", "endgrent"); /* Ignore any errors, we have no way to report them. */ nvlist_destroy(cap_xfer_nvlist(chan, nvl)); } int cap_grp_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds) { nvlist_t *limits, *nvl; unsigned int i; if (cap_limit_get(chan, &limits) < 0) return (-1); if (limits == NULL) { limits = nvlist_create(0); } else { if (nvlist_exists_nvlist(limits, "cmds")) nvlist_free_nvlist(limits, "cmds"); } nvl = nvlist_create(0); for (i = 0; i < ncmds; i++) nvlist_add_null(nvl, cmds[i]); nvlist_move_nvlist(limits, "cmds", nvl); return (cap_limit_set(chan, limits)); } int cap_grp_limit_fields(cap_channel_t *chan, const char * const *fields, size_t nfields) { nvlist_t *limits, *nvl; unsigned int i; if (cap_limit_get(chan, &limits) < 0) return (-1); if (limits == NULL) { limits = nvlist_create(0); } else { if (nvlist_exists_nvlist(limits, "fields")) nvlist_free_nvlist(limits, "fields"); } nvl = nvlist_create(0); for (i = 0; i < nfields; i++) nvlist_add_null(nvl, fields[i]); nvlist_move_nvlist(limits, "fields", nvl); return (cap_limit_set(chan, limits)); } int cap_grp_limit_groups(cap_channel_t *chan, const char * const *names, - size_t nnames, gid_t *gids, size_t ngids) + size_t nnames, const gid_t *gids, size_t ngids) { nvlist_t *limits, *groups; unsigned int i; char nvlname[64]; int n; if (cap_limit_get(chan, &limits) < 0) return (-1); if (limits == NULL) { limits = nvlist_create(0); } else { if (nvlist_exists_nvlist(limits, "groups")) nvlist_free_nvlist(limits, "groups"); } groups = nvlist_create(0); for (i = 0; i < ngids; i++) { n = snprintf(nvlname, sizeof(nvlname), "gid%u", i); assert(n > 0 && n < (int)sizeof(nvlname)); nvlist_add_number(groups, nvlname, (uint64_t)gids[i]); } for (i = 0; i < nnames; i++) { n = snprintf(nvlname, sizeof(nvlname), "gid%u", i); assert(n > 0 && n < (int)sizeof(nvlname)); nvlist_add_string(groups, nvlname, names[i]); } nvlist_move_nvlist(limits, "groups", groups); return (cap_limit_set(chan, limits)); } /* * Service functions. */ static bool grp_allowed_cmd(const nvlist_t *limits, const char *cmd) { if (limits == NULL) return (true); /* * If no limit was set on allowed commands, then all commands * are allowed. */ if (!nvlist_exists_nvlist(limits, "cmds")) return (true); limits = nvlist_get_nvlist(limits, "cmds"); return (nvlist_exists_null(limits, cmd)); } static int grp_allowed_cmds(const nvlist_t *oldlimits, const nvlist_t *newlimits) { const char *name; void *cookie; int type; cookie = NULL; while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { if (type != NV_TYPE_NULL) return (EINVAL); if (!grp_allowed_cmd(oldlimits, name)) return (ENOTCAPABLE); } return (0); } static bool grp_allowed_group(const nvlist_t *limits, const char *gname, gid_t gid) { const char *name; void *cookie; int type; if (limits == NULL) return (true); /* * If no limit was set on allowed groups, then all groups are allowed. */ if (!nvlist_exists_nvlist(limits, "groups")) return (true); limits = nvlist_get_nvlist(limits, "groups"); cookie = NULL; while ((name = nvlist_next(limits, &type, &cookie)) != NULL) { switch (type) { case NV_TYPE_NUMBER: if (gid != (gid_t)-1 && nvlist_get_number(limits, name) == (uint64_t)gid) { return (true); } break; case NV_TYPE_STRING: if (gname != NULL && strcmp(nvlist_get_string(limits, name), gname) == 0) { return (true); } break; default: abort(); } } return (false); } static int grp_allowed_groups(const nvlist_t *oldlimits, const nvlist_t *newlimits) { const char *name, *gname; void *cookie; gid_t gid; int type; cookie = NULL; while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { switch (type) { case NV_TYPE_NUMBER: gid = (gid_t)nvlist_get_number(newlimits, name); gname = NULL; break; case NV_TYPE_STRING: gid = (gid_t)-1; gname = nvlist_get_string(newlimits, name); break; default: return (EINVAL); } if (!grp_allowed_group(oldlimits, gname, gid)) return (ENOTCAPABLE); } return (0); } static bool grp_allowed_field(const nvlist_t *limits, const char *field) { if (limits == NULL) return (true); /* * If no limit was set on allowed fields, then all fields are allowed. */ if (!nvlist_exists_nvlist(limits, "fields")) return (true); limits = nvlist_get_nvlist(limits, "fields"); return (nvlist_exists_null(limits, field)); } static int grp_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits) { const char *name; void *cookie; int type; cookie = NULL; while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { if (type != NV_TYPE_NULL) return (EINVAL); if (!grp_allowed_field(oldlimits, name)) return (ENOTCAPABLE); } return (0); } static bool grp_pack(const nvlist_t *limits, const struct group *grp, nvlist_t *nvl) { char nvlname[64]; int n; if (grp == NULL) return (true); /* * If either name or GID is allowed, we allow it. */ if (!grp_allowed_group(limits, grp->gr_name, grp->gr_gid)) return (false); if (grp_allowed_field(limits, "gr_name")) nvlist_add_string(nvl, "gr_name", grp->gr_name); else nvlist_add_string(nvl, "gr_name", ""); if (grp_allowed_field(limits, "gr_passwd")) nvlist_add_string(nvl, "gr_passwd", grp->gr_passwd); else nvlist_add_string(nvl, "gr_passwd", ""); if (grp_allowed_field(limits, "gr_gid")) nvlist_add_number(nvl, "gr_gid", (uint64_t)grp->gr_gid); else nvlist_add_number(nvl, "gr_gid", (uint64_t)-1); if (grp_allowed_field(limits, "gr_mem") && grp->gr_mem[0] != NULL) { unsigned int ngroups; for (ngroups = 0; grp->gr_mem[ngroups] != NULL; ngroups++) { n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ngroups); assert(n > 0 && n < (ssize_t)sizeof(nvlname)); nvlist_add_string(nvl, nvlname, grp->gr_mem[ngroups]); } nvlist_add_number(nvl, "gr_nmem", (uint64_t)ngroups); } return (true); } static int grp_getgrent(const nvlist_t *limits, const nvlist_t *nvlin __unused, nvlist_t *nvlout) { struct group *grp; for (;;) { errno = 0; grp = getgrent(); if (errno != 0) return (errno); if (grp_pack(limits, grp, nvlout)) return (0); } /* NOTREACHED */ } static int grp_getgrnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) { struct group *grp; const char *name; if (!nvlist_exists_string(nvlin, "name")) return (EINVAL); name = nvlist_get_string(nvlin, "name"); assert(name != NULL); errno = 0; grp = getgrnam(name); if (errno != 0) return (errno); (void)grp_pack(limits, grp, nvlout); return (0); } static int grp_getgrgid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) { struct group *grp; gid_t gid; if (!nvlist_exists_number(nvlin, "gid")) return (EINVAL); gid = (gid_t)nvlist_get_number(nvlin, "gid"); errno = 0; grp = getgrgid(gid); if (errno != 0) return (errno); (void)grp_pack(limits, grp, nvlout); return (0); } static int grp_setgroupent(const nvlist_t *limits __unused, const nvlist_t *nvlin, nvlist_t *nvlout __unused) { int stayopen; if (!nvlist_exists_bool(nvlin, "stayopen")) return (EINVAL); stayopen = nvlist_get_bool(nvlin, "stayopen") ? 1 : 0; return (setgroupent(stayopen) == 0 ? EFAULT : 0); } static int grp_setgrent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused, nvlist_t *nvlout __unused) { setgrent(); return (0); } static int grp_endgrent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused, nvlist_t *nvlout __unused) { endgrent(); return (0); } static int grp_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) { const nvlist_t *limits; const char *name; void *cookie; int error, type; if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "cmds") && !nvlist_exists_nvlist(newlimits, "cmds")) { return (ENOTCAPABLE); } if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "fields") && !nvlist_exists_nvlist(newlimits, "fields")) { return (ENOTCAPABLE); } if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "groups") && !nvlist_exists_nvlist(newlimits, "groups")) { return (ENOTCAPABLE); } cookie = NULL; while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { if (type != NV_TYPE_NVLIST) return (EINVAL); limits = nvlist_get_nvlist(newlimits, name); if (strcmp(name, "cmds") == 0) error = grp_allowed_cmds(oldlimits, limits); else if (strcmp(name, "fields") == 0) error = grp_allowed_fields(oldlimits, limits); else if (strcmp(name, "groups") == 0) error = grp_allowed_groups(oldlimits, limits); else error = EINVAL; if (error != 0) return (error); } return (0); } static int grp_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) { int error; if (!grp_allowed_cmd(limits, cmd)) return (ENOTCAPABLE); if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0) error = grp_getgrent(limits, nvlin, nvlout); else if (strcmp(cmd, "getgrnam") == 0 || strcmp(cmd, "getgrnam_r") == 0) error = grp_getgrnam(limits, nvlin, nvlout); else if (strcmp(cmd, "getgrgid") == 0 || strcmp(cmd, "getgrgid_r") == 0) error = grp_getgrgid(limits, nvlin, nvlout); else if (strcmp(cmd, "setgroupent") == 0) error = grp_setgroupent(limits, nvlin, nvlout); else if (strcmp(cmd, "setgrent") == 0) error = grp_setgrent(limits, nvlin, nvlout); else if (strcmp(cmd, "endgrent") == 0) error = grp_endgrent(limits, nvlin, nvlout); else error = EINVAL; return (error); } CREATE_SERVICE("system.grp", grp_limit, grp_command, 0); Index: head/lib/libcasper/services/cap_grp/cap_grp.h =================================================================== --- head/lib/libcasper/services/cap_grp/cap_grp.h (revision 331145) +++ head/lib/libcasper/services/cap_grp/cap_grp.h (revision 331146) @@ -1,89 +1,89 @@ /*- * Copyright (c) 2013 The FreeBSD Foundation * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _CAP_GRP_H_ #define _CAP_GRP_H_ #ifdef HAVE_CASPER #define WITH_CASPER #endif #ifdef WITH_CASPER struct group *cap_getgrent(cap_channel_t *chan); struct group *cap_getgrnam(cap_channel_t *chan, const char *name); struct group *cap_getgrgid(cap_channel_t *chan, gid_t gid); int cap_getgrent_r(cap_channel_t *chan, struct group *grp, char *buffer, size_t bufsize, struct group **result); int cap_getgrnam_r(cap_channel_t *chan, const char *name, struct group *grp, char *buffer, size_t bufsize, struct group **result); int cap_getgrgid_r(cap_channel_t *chan, gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result); int cap_setgroupent(cap_channel_t *chan, int stayopen); int cap_setgrent(cap_channel_t *chan); void cap_endgrent(cap_channel_t *chan); int cap_grp_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds); int cap_grp_limit_fields(cap_channel_t *chan, const char * const *fields, size_t nfields); int cap_grp_limit_groups(cap_channel_t *chan, const char * const *names, - size_t nnames, gid_t *gids, size_t ngids); + size_t nnames, const gid_t *gids, size_t ngids); #else #define cap_getgrent(chan) getgrent() #define cap_getgrnam(chan, name) getgrnam(name) #define cap_getgrgid(chan, gid) getgrgid(gid) #define cap_setgroupent(chan, stayopen) etgroupent(stayopen) #define endgrent(chan) endgrent() static inline int cap_setgrent(cap_channel_t *chan __unused) { setgrent(); return(0); } #define cap_getgrent_r(chan, grp, buffer, bufsize, result) \ getgrent_r(grp, buffer, bufsize, result) #define cap_getgrnam_r(chan, name, grp, buffer, bufsize, result) \ getgrnam_r(name, grp, buffer, bufsize, result) #define cap_getgrgid_r(chan, gid, grp, buffer, bufsize, result) \ getgrgid_r(gid, grp, buffer, bufsize, result) #define cap_grp_limit_cmds(chan, cmds, ncmds) (0) #define cap_grp_limit_fields(chan, fields, nfields) (0) #define cap_grp_limit_groups(chan, names, nnames, gids, ngids) (0) #endif #endif /* !_CAP_GRP_H_ */