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/types.h>
34 #include <sys/sysctl.h>
42 #include <libcasper.h>
43 #include <libcasper_service.h>
45 #include "cap_sysctl.h"
48 cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp,
49 size_t *oldlenp, const void *newp, size_t newlen)
52 const uint8_t *retoldp;
58 operation |= CAP_SYSCTL_READ;
60 operation |= CAP_SYSCTL_WRITE;
62 nvl = nvlist_create(0);
63 nvlist_add_string(nvl, "cmd", "sysctl");
64 nvlist_add_string(nvl, "name", name);
65 nvlist_add_number(nvl, "operation", (uint64_t)operation);
66 if (oldp == NULL && oldlenp != NULL)
67 nvlist_add_null(nvl, "justsize");
68 else if (oldlenp != NULL)
69 nvlist_add_number(nvl, "oldlen", (uint64_t)*oldlenp);
71 nvlist_add_binary(nvl, "newp", newp, newlen);
72 nvl = cap_xfer_nvlist(chan, nvl, 0);
75 if (nvlist_get_number(nvl, "error") != 0) {
76 errno = (int)nvlist_get_number(nvl, "error");
81 if (oldp == NULL && oldlenp != NULL) {
82 *oldlenp = (size_t)nvlist_get_number(nvl, "oldlen");
83 } else if (oldp != NULL) {
84 retoldp = nvlist_get_binary(nvl, "oldp", &oldlen);
85 memcpy(oldp, retoldp, oldlen);
98 sysctl_check_one(const nvlist_t *nvl, bool islimit)
105 /* NULL nvl is of course invalid. */
108 if (nvlist_error(nvl) != 0)
109 return (nvlist_error(nvl));
111 #define HAS_NAME 0x01
112 #define HAS_OPERATION 0x02
116 while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
117 /* We accept only one 'name' and one 'operation' in nvl. */
118 if (strcmp(name, "name") == 0) {
119 if (type != NV_TYPE_STRING)
121 /* Only one 'name' can be present. */
122 if ((fields & HAS_NAME) != 0)
125 } else if (strcmp(name, "operation") == 0) {
128 if (type != NV_TYPE_NUMBER)
131 * We accept only CAP_SYSCTL_READ and
132 * CAP_SYSCTL_WRITE flags.
134 operation = nvlist_get_number(nvl, name);
135 if ((operation & ~(CAP_SYSCTL_RDWR)) != 0)
137 /* ...but there has to be at least one of them. */
138 if ((operation & (CAP_SYSCTL_RDWR)) == 0)
140 /* Only one 'operation' can be present. */
141 if ((fields & HAS_OPERATION) != 0)
143 fields |= HAS_OPERATION;
144 } else if (islimit) {
145 /* If this is limit, there can be no other fields. */
150 /* Both fields has to be there. */
151 if (fields != (HAS_NAME | HAS_OPERATION))
161 sysctl_allowed(const nvlist_t *limits, const char *chname, uint64_t choperation)
172 while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
173 assert(type == NV_TYPE_NUMBER);
175 operation = nvlist_get_number(limits, name);
176 if ((operation & choperation) != choperation)
179 if ((operation & CAP_SYSCTL_RECURSIVE) == 0) {
180 if (strcmp(name, chname) != 0)
185 namelen = strlen(name);
186 if (strncmp(name, chname, namelen) != 0)
188 if (chname[namelen] != '.' && chname[namelen] != '\0')
199 sysctl_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
207 while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
208 if (type != NV_TYPE_NUMBER)
210 operation = nvlist_get_number(newlimits, name);
211 if ((operation & ~(CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE)) != 0)
213 if ((operation & (CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE)) == 0)
215 if (!sysctl_allowed(oldlimits, name, operation))
216 return (ENOTCAPABLE);
223 sysctl_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
230 size_t oldlen, newlen;
234 if (strcmp(cmd, "sysctl") != 0)
236 error = sysctl_check_one(nvlin, false);
240 name = nvlist_get_string(nvlin, "name");
241 operation = nvlist_get_number(nvlin, "operation");
242 if (!sysctl_allowed(limits, name, operation))
243 return (ENOTCAPABLE);
245 if ((operation & CAP_SYSCTL_WRITE) != 0) {
246 if (!nvlist_exists_binary(nvlin, "newp"))
248 newp = nvlist_get_binary(nvlin, "newp", &newlen);
249 assert(newp != NULL && newlen > 0);
255 if ((operation & CAP_SYSCTL_READ) != 0) {
256 if (nvlist_exists_null(nvlin, "justsize")) {
261 if (!nvlist_exists_number(nvlin, "oldlen"))
263 oldlen = (size_t)nvlist_get_number(nvlin, "oldlen");
266 oldp = calloc(1, oldlen);
277 if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) {
283 if ((operation & CAP_SYSCTL_READ) != 0) {
284 if (nvlist_exists_null(nvlin, "justsize"))
285 nvlist_add_number(nvlout, "oldlen", (uint64_t)oldlen);
287 nvlist_move_binary(nvlout, "oldp", oldp, oldlen);
293 CREATE_SERVICE("system.sysctl", sysctl_limit, sysctl_command, 0);