Index: head/lib/libcasper/services/Makefile =================================================================== --- head/lib/libcasper/services/Makefile +++ head/lib/libcasper/services/Makefile @@ -3,6 +3,7 @@ .include SUBDIR= cap_dns +SUBDIR+= cap_fileargs SUBDIR+= cap_grp SUBDIR+= cap_pwd SUBDIR+= cap_random Index: head/lib/libcasper/services/cap_fileargs/Makefile =================================================================== --- head/lib/libcasper/services/cap_fileargs/Makefile +++ head/lib/libcasper/services/cap_fileargs/Makefile @@ -0,0 +1,35 @@ +# $FreeBSD$ + +SHLIBDIR?= /lib/casper + +.include + +PACKAGE=libcasper + +SHLIB_MAJOR= 1 +INCSDIR?= ${INCLUDEDIR}/casper + +.if ${MK_CASPER} != "no" +SHLIB= cap_fileargs + +SRCS= cap_fileargs.c +.endif + +INCS= cap_fileargs.h + +LIBADD= nv + +CFLAGS+=-I${.CURDIR} + +MAN+= cap_fileargs.3 + +MLINKS+=cap_fileargs.3 libcap_fileargs.3 +MLINKS+=cap_fileargs.3 fileargs_cinit.3 +MLINKS+=cap_fileargs.3 fileargs_cinitnv.3 +MLINKS+=cap_fileargs.3 fileargs_fopen.3 +MLINKS+=cap_fileargs.3 fileargs_free.3 +MLINKS+=cap_fileargs.3 fileargs_init.3 +MLINKS+=cap_fileargs.3 fileargs_initnv.3 +MLINKS+=cap_fileargs.3 fileargs_open.3 + +.include Index: head/lib/libcasper/services/cap_fileargs/cap_fileargs.h =================================================================== --- head/lib/libcasper/services/cap_fileargs/cap_fileargs.h +++ head/lib/libcasper/services/cap_fileargs/cap_fileargs.h @@ -0,0 +1,108 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * 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$ + */ + +#ifndef _FILEARGS_H_ +#define _FILEARGS_H_ + +#include +#include + +#include + +#ifdef WITH_CASPER +struct fileargs; +typedef struct fileargs fileargs_t; + +fileargs_t *fileargs_init(int argc, char *argv[], int flags, mode_t mode, + cap_rights_t *rightsp); +fileargs_t *fileargs_cinit(cap_channel_t *cas, int argc, char *argv[], + int flags, mode_t mode, cap_rights_t *rightsp); +fileargs_t *fileargs_initnv(nvlist_t *limits); +fileargs_t *fileargs_cinitnv(cap_channel_t *cas, nvlist_t *limits); +int fileargs_open(fileargs_t *fa, const char *name); +void fileargs_free(fileargs_t *fa); +FILE *fileargs_fopen(fileargs_t *fa, const char *name, const char *mode); +#else +typedef struct fileargs { + int fa_flags; + mode_t fa_mode; +} fileargs_t; + +static inline fileargs_t * +fileargs_init(int argc __unused, char *argv[] __unused, int flags, mode_t mode, + cap_rights_t *rightsp __unused) { + fileargs_t *fa; + + fa = malloc(sizeof(*fa)); + if (fa != NULL) { + fa->fa_flags = flags; + fa->fa_mode = mode; + } + + return (fa); +} + +static inline fileargs_t * +fileargs_cinit(cap_channel_t *cas __unused, int argc, char *argv[], int flags, + mode_t mode, cap_rights_t *rightsp) +{ + + return (fileargs_init(argc, argv, flags, mode, rightsp)); +} + +static inline fileargs_t * +fileargs_initnv(nvlist_t *limits) +{ + fileargs_t *fa; + + fa = fileargs_init(0, NULL, + nvlist_get_number(limits, "flags"), + dnvlist_get_number(limits, "mode", 0), + NULL); + nvlist_destroy(limits); + + return (fa); +} + +static inline fileargs_t * +fileargs_cinitnv(cap_channel_t *cas __unused, nvlist_t *limits) +{ + + return (fileargs_initnv(limits)); +} + +#define fileargs_open(fa, name) \ + open(name, fa->fa_flags, fa->fa_mode) +#define fileargs_fopen(fa, name, mode) \ + fopen(name, mode) +#define fileargs_free(fa) (free(fa)) +#endif + +#endif /* !_FILEARGS_H_ */ Index: head/lib/libcasper/services/cap_fileargs/cap_fileargs.3 =================================================================== --- head/lib/libcasper/services/cap_fileargs/cap_fileargs.3 +++ head/lib/libcasper/services/cap_fileargs/cap_fileargs.3 @@ -0,0 +1,241 @@ +.\" 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 November 12, 2018 +.Dt CAP_FILEARGS 3 +.Os +.Sh NAME +.Nm fileargs_cinit , +.Nm fileargs_cinitnv , +.Nm fileargs_init , +.Nm fileargs_initnv , +.Nm fileargs_free , +.Nm fileargs_open , +.Nm fileargs_fopen +.Nd "library for handling files in capability mode" +.Sh LIBRARY +.Lb libcap_fileargs +.Sh SYNOPSIS +.In sys/nv.h +.In libcasper.h +.In casper/cap_fileargs.h +.Ft "fileargs_t *" +.Fn fileargs_init "int argc" "char *argv[]" "int flags" "mode_t mode" "cap_rights_t *rightsp" +.Ft "fileargs_t *" +.Fn fileargs_cinit "cap_channel_t *cas" "int argc" "char *argv[]" "int flags" "mode_t mode" "cap_rights_t *rightsp" +.Ft "fileargs_t *" +.Fn fileargs_cinitnv "cap_channel_t *cas" "nvlist_t *limits" +.Ft "fileargs_t *" +.Fn fileargs_initnv "nvlist_t *limits" +.Ft "void" +.Fn fileargs_free "fileargs_t *fa" +.Ft "int" +.Fn fileargs_open "fileargs_t *fa" "const char *name" +.Ft "FILE *" +.Fn fileargs_fopen "fileargs_t *fa" "const char *name" "const char *mode" +.Sh DESCRIPTION +The library is used to simplify Capsicumizing a tools that are using file system. +Idea behind the library is that we are passing a remaining +.Fa argc +and +.Fa argv +which contains a list of files that should be open for this program. +The library will create a service that will serve those files. +.Pp +The function +.Fn fileargs_init +create a service to the +.Nm system.fileargs . +The +.Fa argv +contains a list of files that should be opened. +The argument can be set to +.Dv NULL +which will not create a service and all files will be prohibited to be opened. +The +.Fa argc +argument contains a number of passed files. +The +.Fa flags +argument limits opened files for either execution or reading and/or writing. +The +.Fa mode +argument tells which what mode file should be created if the +.Dv O_CREATE +flag is present . +For more details of the +.Fa flags +and +.Fa mode +arguments see +.Xr open 2 . +The +.Fa rightsp +argument contains a list of the capability rights which file should be limited to. +For more details of the capability rights see +.Xr cap_rights_init 3 . +.Pp +The function +.Fn fileargs_cinit +is equivalent to +.Fn fileargs_init +except that the connection to the Casper needs to be provided. +.Pp +The functions +.Fn fileargs_ininv +and +.Fn fileargs_cininv +are respectively equivalent to +.Fn fileargs_init +and +.Fn fileargs_cinit +expect that all arguments all provided as +.Xr nvlist 9 . +For details see +.Sx LIMITS . +.Pp +The +.Fa fileargs_free +close connection to the +.Nm system.filerags +service and free are structures. +The function handle +.Dv NULL +argument. +.Pp +The functions +.Fn fileargs_open +and +.Fn fileargs_fopen +are respectively equivalent to +.Xr open 2 +and +.Xr fopen 3 +expect that all arguments are fetched from the +.Va fileargs_t +structure. +.Sh LIMITS +This section describe which values and types should be used to pass arguments to the +.Fa system.filerags +through the +.Fn fileargs_ininv +and +.Fn fileargs_cinit +functions. +The +.Xr nvlist 9 +for that functions must contain the following values and types: +.Bl -ohang -offset indent +.It flags ( NV_TYPE_NUMBER ) +The +.Va flags +limits opened files for either execution or reading and/or writing. +.It mode (NV_TYPE_NUMBER) +If in the +.Va flags +argument the +.Dv O_CREATE +flag was defined the +.Xr nvlist 9 +must contain the +.Va mode . +The +.Va mode +argument tells which what mode file should be created. +.El +.Pp +The +.Xr nvlist 9 +for that functions may contain the following values and types: +.Bl -ohang -offset indent +.It cap_rights ( NV_TYPE_BINARY ) +The +.Va cap_rights +argument contains a list of the capability rights which file should be limited to. +.It ( NV_TYPE_NULL ) +Any number of +.Dv NV_TYPE_NULL +where the name of the element is name of the file which can be opened. +.Sh EXAMPLES +The following example first parse some options and then create the +.Nm system.filerags +service with remaining arguments. +.Bd -literal +int ch, fd, i; +cap_rights_t rights; +fileargs_t *fa; + +while ((ch = getopt(argc, argv, "h")) != -1) { + switch (ch) { + case 'h': + default: + usage(); + } +} + +argc -= optind; +argv += optind; + +/* Create capability to the system.fileargs service. */ +fa = fileargs_init(argc, argv, O_RDONLY, 0, + cap_rights_init(&rights, CAP_READ)); +if (fa == NULL) + err(1, "unable to open system.fileargs service"); + +/* Enter capability mode sandbox. */ +if (cap_enter() < 0 && errno != ENOSYS) + err(1, "unable to enter capability mode"); + +/* Open files. */ +for (i = 0; i < argc; i++) { + fd = fileargs_open(fa, argv[i]); + if (fd < 0) + err(1, "unable to open file %s", argv[i]); + printf("File %s opened in capability mode\n", argv[i]); + close(fd); +} + +fileargs_free(fa); +.Ed +.Sh SEE ALSO +.Xr cap_enter 2 , +.Xr open 2 , +.Xr cap_rights_init 3 , +.Xr err 3 , +.Xr fopen 3, +.Xr getopt 3, +.Xr capsicum 4 , +.Xr nv 9 +.Sh BUGS +The +.Lb cap_fileargs +included in +.Fx +is considered experimental, and should not be deployed in production +environments without careful consideration of the risks associated with +the use of experimental operating system features. +.Sh AUTHORS +.An Mariusz Zaborski Aq Mt oshogbo@FreeBSD.org Index: head/lib/libcasper/services/cap_fileargs/cap_fileargs.c =================================================================== --- head/lib/libcasper/services/cap_fileargs/cap_fileargs.c +++ head/lib/libcasper/services/cap_fileargs/cap_fileargs.c @@ -0,0 +1,505 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "cap_fileargs.h" + +#define CACHE_SIZE 128 + +#define FILEARGS_MAGIC 0xFA00FA00 + +struct fileargs { + uint32_t fa_magic; + nvlist_t *fa_cache; + cap_channel_t *fa_chann; + int fa_fdflags; +}; + +static int +fileargs_get_cache(fileargs_t *fa, const char *name) +{ + int fd; + const nvlist_t *nvl; + nvlist_t *tnvl; + + assert(fa != NULL); + assert(fa->fa_magic == FILEARGS_MAGIC); + assert(name != NULL); + + if (fa->fa_cache == NULL) + return (-1); + + if ((fa->fa_fdflags & O_CREAT) != 0) + return (-1); + + nvl = dnvlist_get_nvlist(fa->fa_cache, name, NULL); + if (nvl == NULL) + return (-1); + + tnvl = nvlist_take_nvlist(fa->fa_cache, name); + fd = nvlist_take_descriptor(tnvl, "fd"); + nvlist_destroy(tnvl); + + if ((fa->fa_fdflags & O_CLOEXEC) != O_CLOEXEC) { + if (fcntl(fd, F_SETFD, fa->fa_fdflags) == -1) { + close(fd); + return (-1); + } + } + + return (fd); +} + +static void +fileargs_set_cache(fileargs_t *fa, nvlist_t *nvl) +{ + + nvlist_destroy(fa->fa_cache); + fa->fa_cache = nvl; +} + +static nvlist_t* +fileargs_fetch(fileargs_t *fa, const char *name) +{ + nvlist_t *nvl; + int serrno; + + assert(fa != NULL); + assert(name != NULL); + + nvl = nvlist_create(NV_FLAG_NO_UNIQUE); + nvlist_add_string(nvl, "cmd", "open"); + nvlist_add_string(nvl, "name", name); + + nvl = cap_xfer_nvlist(fa->fa_chann, nvl); + if (nvl == NULL) + return (NULL); + + if (nvlist_get_number(nvl, "error") != 0) { + serrno = (int)nvlist_get_number(nvl, "error"); + nvlist_destroy(nvl); + errno = serrno; + return (NULL); + } + + return (nvl); +} + +static nvlist_t * +fileargs_create_limit(int argc, const char * const *argv, int flags, + mode_t mode, cap_rights_t *rightsp) +{ + nvlist_t *limits; + int i; + + limits = nvlist_create(NV_FLAG_NO_UNIQUE); + if (limits == NULL) + return (NULL); + + nvlist_add_number(limits, "flags", flags); + if (rightsp != NULL) { + nvlist_add_binary(limits, "cap_rights", rightsp, + sizeof(*rightsp)); + } + if ((flags & O_CREAT) != 0) + nvlist_add_number(limits, "mode", (uint64_t)mode); + + for (i = 0; i < argc; i++) { + nvlist_add_null(limits, argv[i]); + } + + return (limits); +} + +static fileargs_t * +fileargs_create(cap_channel_t *chan, int fdflags) +{ + fileargs_t *fa; + + fa = malloc(sizeof(*fa)); + if (fa != NULL) { + fa->fa_cache = NULL; + fa->fa_chann = chan; + fa->fa_fdflags = fdflags; + fa->fa_magic = FILEARGS_MAGIC; + } + + return (fa); +} + +fileargs_t * +fileargs_init(int argc, char *argv[], int flags, mode_t mode, + cap_rights_t *rightsp) +{ + nvlist_t *limits; + + if (argv <= 0 || argv == NULL) { + return (fileargs_create(NULL, 0)); + } + + limits = fileargs_create_limit(argc, (const char * const *)argv, flags, + mode, rightsp); + if (limits == NULL) + return (NULL); + + return (fileargs_initnv(limits)); +} + +fileargs_t * +fileargs_cinit(cap_channel_t *cas, int argc, char *argv[], int flags, + mode_t mode, cap_rights_t *rightsp) +{ + nvlist_t *limits; + + if (argv <= 0 || argv == NULL) { + return (fileargs_create(NULL, 0)); + } + + limits = fileargs_create_limit(argc, (const char * const *)argv, flags, + mode, rightsp); + if (limits == NULL) + return (NULL); + + return (fileargs_cinitnv(cas, limits)); +} + +fileargs_t * +fileargs_initnv(nvlist_t *limits) +{ + cap_channel_t *cas; + fileargs_t *fa; + + if (limits == NULL) { + return (fileargs_create(NULL, 0)); + } + + cas = cap_init(); + if (cas == NULL) { + nvlist_destroy(limits); + return (NULL); + } + + fa = fileargs_cinitnv(cas, limits); + cap_close(cas); + + return (fa); +} + +fileargs_t * +fileargs_cinitnv(cap_channel_t *cas, nvlist_t *limits) +{ + cap_channel_t *chann; + fileargs_t *fa; + int serrno, ret; + int flags; + + assert(cas != NULL); + + if (limits == NULL) { + return (fileargs_create(NULL, 0)); + } + + chann = NULL; + fa = NULL; + + chann = cap_service_open(cas, "system.fileargs"); + if (chann == NULL) { + nvlist_destroy(limits); + return (NULL); + } + + flags = nvlist_get_number(limits, "flags"); + + /* Limits are consumed no need to free them. */ + ret = cap_limit_set(chann, limits); + if (ret < 0) + goto out; + + fa = fileargs_create(chann, flags); + if (fa == NULL) + goto out; + + return (fa); +out: + serrno = errno; + if (chann != NULL) + cap_close(chann); + errno = serrno; + return (NULL); +} + +int +fileargs_open(fileargs_t *fa, const char *name) +{ + int fd; + nvlist_t *nvl; + char *cmd; + + assert(fa != NULL); + assert(fa->fa_magic == FILEARGS_MAGIC); + + if (name == NULL) { + errno = EINVAL; + return (-1); + } + + if (fa->fa_chann == NULL) { + errno = ENOTCAPABLE; + return (-1); + } + + fd = fileargs_get_cache(fa, name); + if (fd != -1) + return (fd); + + nvl = fileargs_fetch(fa, name); + if (nvl == NULL) + return (-1); + + fd = nvlist_take_descriptor(nvl, "fd"); + cmd = nvlist_take_string(nvl, "cmd"); + if (strcmp(cmd, "cache") == 0) + fileargs_set_cache(fa, nvl); + else + nvlist_destroy(nvl); + free(cmd); + + return (fd); +} + +FILE * +fileargs_fopen(fileargs_t *fa, const char *name, const char *mode) +{ + int fd; + + if ((fd = fileargs_open(fa, name)) < 0) { + return (NULL); + } + + return (fdopen(fd, mode)); +} + +void +fileargs_free(fileargs_t *fa) +{ + + if (fa == NULL) + return; + + assert(fa->fa_magic == FILEARGS_MAGIC); + + nvlist_destroy(fa->fa_cache); + if (fa->fa_chann != NULL) { + cap_close(fa->fa_chann); + } + explicit_bzero(&fa->fa_magic, sizeof(fa->fa_magic)); + free(fa); +} + +/* + * Service functions. + */ + +static const char *lastname; +static void *cacheposition; +static bool allcached; +static const cap_rights_t *caprightsp; +static int capflags; +static mode_t capmode; + +static int +open_file(const char *name) +{ + int fd, serrno; + + if ((capflags & O_CREAT) == 0) + fd = open(name, capflags); + else + fd = open(name, capflags, capmode); + if (fd < 0) + return (-1); + + if (caprightsp != NULL) { + if (cap_rights_limit(fd, caprightsp) < 0) { + serrno = errno; + close(fd); + errno = serrno; + return (-1); + } + } + + return (fd); +} + +static void +fileargs_add_cache(nvlist_t *nvlout, const nvlist_t *limits, + const char *curent_name) +{ + int type, i, fd; + void *cookie; + nvlist_t *new; + const char *fname; + + if ((capflags & O_CREAT) != 0) { + allcached = true; + return; + } + + cookie = cacheposition; + for (i = 0; i < CACHE_SIZE + 1; i++) { + fname = nvlist_next(limits, &type, &cookie); + if (fname == NULL) { + cacheposition = NULL; + lastname = NULL; + allcached = true; + return; + } + /* We doing that to catch next element name. */ + if (i == CACHE_SIZE) { + break; + } + + if (type != NV_TYPE_NULL || + (curent_name != NULL && strcmp(fname, curent_name) == 0)) { + curent_name = NULL; + i--; + continue; + } + + fd = open_file(fname); + if (fd < 0) { + i--; + continue; + } + + new = nvlist_create(NV_FLAG_NO_UNIQUE); + nvlist_move_descriptor(new, "fd", fd); + nvlist_add_nvlist(nvlout, fname, new); + } + cacheposition = cookie; + lastname = fname; +} + +static bool +fileargs_allowed(const nvlist_t *limits, const nvlist_t *request) +{ + const char *name; + + name = dnvlist_get_string(request, "name", NULL); + if (name == NULL) + return (false); + + /* Fast path. */ + if (lastname != NULL && strcmp(name, lastname) == 0) + return (true); + + if (!nvlist_exists_null(limits, name)) + return (false); + + return (true); +} + +static int +fileargs_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) +{ + + if (oldlimits != NULL) + return (ENOTCAPABLE); + + capflags = (int)dnvlist_get_number(newlimits, "flags", 0); + if ((capflags & O_CREAT) != 0) + capmode = (mode_t)nvlist_get_number(newlimits, "mode"); + else + capmode = 0; + + caprightsp = dnvlist_get_binary(newlimits, "cap_rights", NULL, NULL, 0); + + return (0); +} + +static int +fileargs_command_open(const nvlist_t *limits, nvlist_t *nvlin, + nvlist_t *nvlout) +{ + int fd; + const char *name; + + if (limits == NULL) + return (ENOTCAPABLE); + + if (!fileargs_allowed(limits, nvlin)) + return (ENOTCAPABLE); + + name = nvlist_get_string(nvlin, "name"); + + fd = open_file(name); + if (fd < 0) + return (errno); + + if (!allcached && (lastname == NULL || + strcmp(name, lastname) == 0)) { + nvlist_add_string(nvlout, "cmd", "cache"); + fileargs_add_cache(nvlout, limits, name); + } else { + nvlist_add_string(nvlout, "cmd", "open"); + } + nvlist_move_descriptor(nvlout, "fd", fd); + return (0); +} + +static int +fileargs_command(const char *cmd, const nvlist_t *limits, + nvlist_t *nvlin, nvlist_t *nvlout) +{ + + if (strcmp(cmd, "open") == 0) + return (fileargs_command_open(limits, nvlin, nvlout)); + + return (EINVAL); +} + +CREATE_SERVICE("system.fileargs", fileargs_limit, fileargs_command, + CASPER_SERVICE_FD | CASPER_SERVICE_STDIO | CASPER_SERVICE_NO_UNIQ_LIMITS); Index: head/share/mk/src.libnames.mk =================================================================== --- head/share/mk/src.libnames.mk +++ head/share/mk/src.libnames.mk @@ -75,6 +75,7 @@ cam \ casper \ cap_dns \ + cap_fileargs \ cap_grp \ cap_pwd \ cap_random \ @@ -238,6 +239,7 @@ _DP_kvm= elf _DP_casper= nv _DP_cap_dns= nv +_DP_cap_fileargs= nv _DP_cap_grp= nv _DP_cap_pwd= nv _DP_cap_random= nv