1cdd6ea94SMariusz Zaborski /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3cdd6ea94SMariusz Zaborski  *
4dcdad299SMariusz Zaborski  * Copyright (c) 2018-2021 Mariusz Zaborski <oshogbo@FreeBSD.org>
5cdd6ea94SMariusz Zaborski  * All rights reserved.
6cdd6ea94SMariusz Zaborski  *
7cdd6ea94SMariusz Zaborski  * Redistribution and use in source and binary forms, with or without
8cdd6ea94SMariusz Zaborski  * modification, are permitted provided that the following conditions
9cdd6ea94SMariusz Zaborski  * are met:
10cdd6ea94SMariusz Zaborski  * 1. Redistributions of source code must retain the above copyright
11cdd6ea94SMariusz Zaborski  *    notice, this list of conditions and the following disclaimer.
12cdd6ea94SMariusz Zaborski  * 2. Redistributions in binary form must reproduce the above copyright
13cdd6ea94SMariusz Zaborski  *    notice, this list of conditions and the following disclaimer in the
14cdd6ea94SMariusz Zaborski  *    documentation and/or other materials provided with the distribution.
15cdd6ea94SMariusz Zaborski  *
16cdd6ea94SMariusz Zaborski  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17cdd6ea94SMariusz Zaborski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18cdd6ea94SMariusz Zaborski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19cdd6ea94SMariusz Zaborski  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20cdd6ea94SMariusz Zaborski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21cdd6ea94SMariusz Zaborski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22cdd6ea94SMariusz Zaborski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23cdd6ea94SMariusz Zaborski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24cdd6ea94SMariusz Zaborski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25cdd6ea94SMariusz Zaborski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26cdd6ea94SMariusz Zaborski  * SUCH DAMAGE.
27cdd6ea94SMariusz Zaborski  */
28cdd6ea94SMariusz Zaborski 
29cdd6ea94SMariusz Zaborski #include <sys/types.h>
30cdd6ea94SMariusz Zaborski #include <sys/capsicum.h>
31cdd6ea94SMariusz Zaborski #include <sys/sysctl.h>
32cdd6ea94SMariusz Zaborski #include <sys/cnv.h>
33cdd6ea94SMariusz Zaborski #include <sys/dnv.h>
34cdd6ea94SMariusz Zaborski #include <sys/nv.h>
357b558caeSEd Maste #include <sys/stat.h>
36cdd6ea94SMariusz Zaborski 
37cdd6ea94SMariusz Zaborski #include <assert.h>
38cdd6ea94SMariusz Zaborski #include <errno.h>
39cdd6ea94SMariusz Zaborski #include <stdlib.h>
40cdd6ea94SMariusz Zaborski #include <string.h>
41cdd6ea94SMariusz Zaborski #include <unistd.h>
42cdd6ea94SMariusz Zaborski 
43cdd6ea94SMariusz Zaborski #include <libcasper.h>
44cdd6ea94SMariusz Zaborski #include <libcasper_service.h>
45cdd6ea94SMariusz Zaborski 
46cdd6ea94SMariusz Zaborski #include "cap_fileargs.h"
47cdd6ea94SMariusz Zaborski 
48cdd6ea94SMariusz Zaborski #define CACHE_SIZE	128
49cdd6ea94SMariusz Zaborski 
50cdd6ea94SMariusz Zaborski #define FILEARGS_MAGIC	0xFA00FA00
51cdd6ea94SMariusz Zaborski 
52cdd6ea94SMariusz Zaborski struct fileargs {
53cdd6ea94SMariusz Zaborski 	uint32_t	 fa_magic;
54cdd6ea94SMariusz Zaborski 	nvlist_t	*fa_cache;
55cdd6ea94SMariusz Zaborski 	cap_channel_t	*fa_chann;
56cdd6ea94SMariusz Zaborski 	int		 fa_fdflags;
57cdd6ea94SMariusz Zaborski };
58cdd6ea94SMariusz Zaborski 
59cdd6ea94SMariusz Zaborski static int
fileargs_get_lstat_cache(fileargs_t * fa,const char * name,struct stat * sb)607b558caeSEd Maste fileargs_get_lstat_cache(fileargs_t *fa, const char *name, struct stat *sb)
617b558caeSEd Maste {
627b558caeSEd Maste 	const nvlist_t *nvl;
637b558caeSEd Maste 	size_t size;
647b558caeSEd Maste 	const void *buf;
657b558caeSEd Maste 
667b558caeSEd Maste 	assert(fa != NULL);
677b558caeSEd Maste 	assert(fa->fa_magic == FILEARGS_MAGIC);
687b558caeSEd Maste 	assert(name != NULL);
697b558caeSEd Maste 
707b558caeSEd Maste 	if (fa->fa_cache == NULL)
717b558caeSEd Maste 		return (-1);
727b558caeSEd Maste 
737b558caeSEd Maste 	nvl = dnvlist_get_nvlist(fa->fa_cache, name, NULL);
747b558caeSEd Maste 	if (nvl == NULL)
757b558caeSEd Maste 		return (-1);
767b558caeSEd Maste 
777b558caeSEd Maste 	if (!nvlist_exists_binary(nvl, "stat")) {
787b558caeSEd Maste 		return (-1);
797b558caeSEd Maste 	}
807b558caeSEd Maste 
817b558caeSEd Maste 	buf = nvlist_get_binary(nvl, "stat", &size);
827b558caeSEd Maste 	assert(size == sizeof(*sb));
837b558caeSEd Maste 	memcpy(sb, buf, size);
847b558caeSEd Maste 
857b558caeSEd Maste 	return (0);
867b558caeSEd Maste }
877b558caeSEd Maste 
887b558caeSEd Maste static int
fileargs_get_fd_cache(fileargs_t * fa,const char * name)897b558caeSEd Maste fileargs_get_fd_cache(fileargs_t *fa, const char *name)
90cdd6ea94SMariusz Zaborski {
91cdd6ea94SMariusz Zaborski 	int fd;
92cdd6ea94SMariusz Zaborski 	const nvlist_t *nvl;
93cdd6ea94SMariusz Zaborski 	nvlist_t *tnvl;
94cdd6ea94SMariusz Zaborski 
95cdd6ea94SMariusz Zaborski 	assert(fa != NULL);
96cdd6ea94SMariusz Zaborski 	assert(fa->fa_magic == FILEARGS_MAGIC);
97cdd6ea94SMariusz Zaborski 	assert(name != NULL);
98cdd6ea94SMariusz Zaborski 
99cdd6ea94SMariusz Zaborski 	if (fa->fa_cache == NULL)
100cdd6ea94SMariusz Zaborski 		return (-1);
101cdd6ea94SMariusz Zaborski 
102cdd6ea94SMariusz Zaborski 	if ((fa->fa_fdflags & O_CREAT) != 0)
103cdd6ea94SMariusz Zaborski 		return (-1);
104cdd6ea94SMariusz Zaborski 
105cdd6ea94SMariusz Zaborski 	nvl = dnvlist_get_nvlist(fa->fa_cache, name, NULL);
106cdd6ea94SMariusz Zaborski 	if (nvl == NULL)
107cdd6ea94SMariusz Zaborski 		return (-1);
108cdd6ea94SMariusz Zaborski 
109cdd6ea94SMariusz Zaborski 	tnvl = nvlist_take_nvlist(fa->fa_cache, name);
1107b558caeSEd Maste 
1117b558caeSEd Maste 	if (!nvlist_exists_descriptor(tnvl, "fd")) {
1127b558caeSEd Maste 		nvlist_destroy(tnvl);
1137b558caeSEd Maste 		return (-1);
1147b558caeSEd Maste 	}
1157b558caeSEd Maste 
116cdd6ea94SMariusz Zaborski 	fd = nvlist_take_descriptor(tnvl, "fd");
117cdd6ea94SMariusz Zaborski 	nvlist_destroy(tnvl);
118cdd6ea94SMariusz Zaborski 
119cdd6ea94SMariusz Zaborski 	if ((fa->fa_fdflags & O_CLOEXEC) != O_CLOEXEC) {
120cdd6ea94SMariusz Zaborski 		if (fcntl(fd, F_SETFD, fa->fa_fdflags) == -1) {
121cdd6ea94SMariusz Zaborski 			close(fd);
122cdd6ea94SMariusz Zaborski 			return (-1);
123cdd6ea94SMariusz Zaborski 		}
124cdd6ea94SMariusz Zaborski 	}
125cdd6ea94SMariusz Zaborski 
126cdd6ea94SMariusz Zaborski 	return (fd);
127cdd6ea94SMariusz Zaborski }
128cdd6ea94SMariusz Zaborski 
129cdd6ea94SMariusz Zaborski static void
fileargs_set_cache(fileargs_t * fa,nvlist_t * nvl)130cdd6ea94SMariusz Zaborski fileargs_set_cache(fileargs_t *fa, nvlist_t *nvl)
131cdd6ea94SMariusz Zaborski {
132cdd6ea94SMariusz Zaborski 
133cdd6ea94SMariusz Zaborski 	nvlist_destroy(fa->fa_cache);
134cdd6ea94SMariusz Zaborski 	fa->fa_cache = nvl;
135cdd6ea94SMariusz Zaborski }
136cdd6ea94SMariusz Zaborski 
137cdd6ea94SMariusz Zaborski static nvlist_t*
fileargs_fetch(fileargs_t * fa,const char * name,const char * cmd)1387b558caeSEd Maste fileargs_fetch(fileargs_t *fa, const char *name, const char *cmd)
139cdd6ea94SMariusz Zaborski {
140cdd6ea94SMariusz Zaborski 	nvlist_t *nvl;
141cdd6ea94SMariusz Zaborski 	int serrno;
142cdd6ea94SMariusz Zaborski 
143cdd6ea94SMariusz Zaborski 	assert(fa != NULL);
144cdd6ea94SMariusz Zaborski 	assert(name != NULL);
145cdd6ea94SMariusz Zaborski 
146cdd6ea94SMariusz Zaborski 	nvl = nvlist_create(NV_FLAG_NO_UNIQUE);
1477b558caeSEd Maste 	nvlist_add_string(nvl, "cmd", cmd);
148cdd6ea94SMariusz Zaborski 	nvlist_add_string(nvl, "name", name);
149cdd6ea94SMariusz Zaborski 
150cdd6ea94SMariusz Zaborski 	nvl = cap_xfer_nvlist(fa->fa_chann, nvl);
151cdd6ea94SMariusz Zaborski 	if (nvl == NULL)
152cdd6ea94SMariusz Zaborski 		return (NULL);
153cdd6ea94SMariusz Zaborski 
154cdd6ea94SMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
155cdd6ea94SMariusz Zaborski 		serrno = (int)nvlist_get_number(nvl, "error");
156cdd6ea94SMariusz Zaborski 		nvlist_destroy(nvl);
157cdd6ea94SMariusz Zaborski 		errno = serrno;
158cdd6ea94SMariusz Zaborski 		return (NULL);
159cdd6ea94SMariusz Zaborski 	}
160cdd6ea94SMariusz Zaborski 
161cdd6ea94SMariusz Zaborski 	return (nvl);
162cdd6ea94SMariusz Zaborski }
163cdd6ea94SMariusz Zaborski 
164cdd6ea94SMariusz Zaborski static nvlist_t *
fileargs_create_limit(int argc,const char * const * argv,int flags,mode_t mode,cap_rights_t * rightsp,int operations)165cdd6ea94SMariusz Zaborski fileargs_create_limit(int argc, const char * const *argv, int flags,
1667b558caeSEd Maste     mode_t mode, cap_rights_t *rightsp, int operations)
167cdd6ea94SMariusz Zaborski {
168cdd6ea94SMariusz Zaborski 	nvlist_t *limits;
169cdd6ea94SMariusz Zaborski 	int i;
170cdd6ea94SMariusz Zaborski 
171cdd6ea94SMariusz Zaborski 	limits = nvlist_create(NV_FLAG_NO_UNIQUE);
172cdd6ea94SMariusz Zaborski 	if (limits == NULL)
173cdd6ea94SMariusz Zaborski 		return (NULL);
174cdd6ea94SMariusz Zaborski 
175cdd6ea94SMariusz Zaborski 	nvlist_add_number(limits, "flags", flags);
1767b558caeSEd Maste 	nvlist_add_number(limits, "operations", operations);
177cdd6ea94SMariusz Zaborski 	if (rightsp != NULL) {
178cdd6ea94SMariusz Zaborski 		nvlist_add_binary(limits, "cap_rights", rightsp,
179cdd6ea94SMariusz Zaborski 		    sizeof(*rightsp));
180cdd6ea94SMariusz Zaborski 	}
181cdd6ea94SMariusz Zaborski 	if ((flags & O_CREAT) != 0)
182cdd6ea94SMariusz Zaborski 		nvlist_add_number(limits, "mode", (uint64_t)mode);
183cdd6ea94SMariusz Zaborski 
184cdd6ea94SMariusz Zaborski 	for (i = 0; i < argc; i++) {
18595097753SMariusz Zaborski 		if (strlen(argv[i]) >= MAXPATHLEN) {
18695097753SMariusz Zaborski 			nvlist_destroy(limits);
18795097753SMariusz Zaborski 			errno = ENAMETOOLONG;
18895097753SMariusz Zaborski 			return (NULL);
18995097753SMariusz Zaborski 		}
190cdd6ea94SMariusz Zaborski 		nvlist_add_null(limits, argv[i]);
191cdd6ea94SMariusz Zaborski 	}
192cdd6ea94SMariusz Zaborski 
193cdd6ea94SMariusz Zaborski 	return (limits);
194cdd6ea94SMariusz Zaborski }
195cdd6ea94SMariusz Zaborski 
196cdd6ea94SMariusz Zaborski static fileargs_t *
fileargs_create(cap_channel_t * chan,int fdflags)197cdd6ea94SMariusz Zaborski fileargs_create(cap_channel_t *chan, int fdflags)
198cdd6ea94SMariusz Zaborski {
199cdd6ea94SMariusz Zaborski 	fileargs_t *fa;
200cdd6ea94SMariusz Zaborski 
201cdd6ea94SMariusz Zaborski 	fa = malloc(sizeof(*fa));
202cdd6ea94SMariusz Zaborski 	if (fa != NULL) {
203cdd6ea94SMariusz Zaborski 		fa->fa_cache = NULL;
204cdd6ea94SMariusz Zaborski 		fa->fa_chann = chan;
205cdd6ea94SMariusz Zaborski 		fa->fa_fdflags = fdflags;
206cdd6ea94SMariusz Zaborski 		fa->fa_magic = FILEARGS_MAGIC;
207cdd6ea94SMariusz Zaborski 	}
208cdd6ea94SMariusz Zaborski 
209cdd6ea94SMariusz Zaborski 	return (fa);
210cdd6ea94SMariusz Zaborski }
211cdd6ea94SMariusz Zaborski 
212cdd6ea94SMariusz Zaborski fileargs_t *
fileargs_init(int argc,char * argv[],int flags,mode_t mode,cap_rights_t * rightsp,int operations)213cdd6ea94SMariusz Zaborski fileargs_init(int argc, char *argv[], int flags, mode_t mode,
2147b558caeSEd Maste     cap_rights_t *rightsp, int operations)
215cdd6ea94SMariusz Zaborski {
216cdd6ea94SMariusz Zaborski 	nvlist_t *limits;
217cdd6ea94SMariusz Zaborski 
2182607c01bSMariusz Zaborski 	if (argc <= 0 || argv == NULL) {
219cdd6ea94SMariusz Zaborski 		return (fileargs_create(NULL, 0));
220cdd6ea94SMariusz Zaborski 	}
221cdd6ea94SMariusz Zaborski 
222cdd6ea94SMariusz Zaborski 	limits = fileargs_create_limit(argc, (const char * const *)argv, flags,
2237b558caeSEd Maste 	   mode, rightsp, operations);
224cdd6ea94SMariusz Zaborski 	if (limits == NULL)
225cdd6ea94SMariusz Zaborski 		return (NULL);
226cdd6ea94SMariusz Zaborski 
227cdd6ea94SMariusz Zaborski 	return (fileargs_initnv(limits));
228cdd6ea94SMariusz Zaborski }
229cdd6ea94SMariusz Zaborski 
230cdd6ea94SMariusz Zaborski fileargs_t *
fileargs_cinit(cap_channel_t * cas,int argc,char * argv[],int flags,mode_t mode,cap_rights_t * rightsp,int operations)231cdd6ea94SMariusz Zaborski fileargs_cinit(cap_channel_t *cas, int argc, char *argv[], int flags,
2327b558caeSEd Maste      mode_t mode, cap_rights_t *rightsp, int operations)
233cdd6ea94SMariusz Zaborski {
234cdd6ea94SMariusz Zaborski 	nvlist_t *limits;
235cdd6ea94SMariusz Zaborski 
2362607c01bSMariusz Zaborski 	if (argc <= 0 || argv == NULL) {
237cdd6ea94SMariusz Zaborski 		return (fileargs_create(NULL, 0));
238cdd6ea94SMariusz Zaborski 	}
239cdd6ea94SMariusz Zaborski 
240cdd6ea94SMariusz Zaborski 	limits = fileargs_create_limit(argc, (const char * const *)argv, flags,
2417b558caeSEd Maste 	   mode, rightsp, operations);
242cdd6ea94SMariusz Zaborski 	if (limits == NULL)
243cdd6ea94SMariusz Zaborski 		return (NULL);
244cdd6ea94SMariusz Zaborski 
245cdd6ea94SMariusz Zaborski 	return (fileargs_cinitnv(cas, limits));
246cdd6ea94SMariusz Zaborski }
247cdd6ea94SMariusz Zaborski 
248cdd6ea94SMariusz Zaborski fileargs_t *
fileargs_initnv(nvlist_t * limits)249cdd6ea94SMariusz Zaborski fileargs_initnv(nvlist_t *limits)
250cdd6ea94SMariusz Zaborski {
251cdd6ea94SMariusz Zaborski         cap_channel_t *cas;
252cdd6ea94SMariusz Zaborski 	fileargs_t *fa;
253cdd6ea94SMariusz Zaborski 
254cdd6ea94SMariusz Zaborski 	if (limits == NULL) {
255cdd6ea94SMariusz Zaborski 		return (fileargs_create(NULL, 0));
256cdd6ea94SMariusz Zaborski 	}
257cdd6ea94SMariusz Zaborski 
258cdd6ea94SMariusz Zaborski         cas = cap_init();
259cdd6ea94SMariusz Zaborski         if (cas == NULL) {
260cdd6ea94SMariusz Zaborski 		nvlist_destroy(limits);
261cdd6ea94SMariusz Zaborski                 return (NULL);
262cdd6ea94SMariusz Zaborski 	}
263cdd6ea94SMariusz Zaborski 
264cdd6ea94SMariusz Zaborski         fa = fileargs_cinitnv(cas, limits);
265cdd6ea94SMariusz Zaborski         cap_close(cas);
266cdd6ea94SMariusz Zaborski 
267cdd6ea94SMariusz Zaborski 	return (fa);
268cdd6ea94SMariusz Zaborski }
269cdd6ea94SMariusz Zaborski 
270cdd6ea94SMariusz Zaborski fileargs_t *
fileargs_cinitnv(cap_channel_t * cas,nvlist_t * limits)271cdd6ea94SMariusz Zaborski fileargs_cinitnv(cap_channel_t *cas, nvlist_t *limits)
272cdd6ea94SMariusz Zaborski {
273cdd6ea94SMariusz Zaborski 	cap_channel_t *chann;
274cdd6ea94SMariusz Zaborski 	fileargs_t *fa;
2751e9ce60aSMariusz Zaborski 	int flags, ret, serrno;
276cdd6ea94SMariusz Zaborski 
277cdd6ea94SMariusz Zaborski 	assert(cas != NULL);
278cdd6ea94SMariusz Zaborski 
279cdd6ea94SMariusz Zaborski 	if (limits == NULL) {
280cdd6ea94SMariusz Zaborski 		return (fileargs_create(NULL, 0));
281cdd6ea94SMariusz Zaborski 	}
282cdd6ea94SMariusz Zaborski 
283cdd6ea94SMariusz Zaborski 	chann = NULL;
284cdd6ea94SMariusz Zaborski 	fa = NULL;
285cdd6ea94SMariusz Zaborski 
286cdd6ea94SMariusz Zaborski 	chann = cap_service_open(cas, "system.fileargs");
287cdd6ea94SMariusz Zaborski 	if (chann == NULL) {
288cdd6ea94SMariusz Zaborski 		nvlist_destroy(limits);
289cdd6ea94SMariusz Zaborski 		return (NULL);
290cdd6ea94SMariusz Zaborski 	}
291cdd6ea94SMariusz Zaborski 
292cdd6ea94SMariusz Zaborski 	flags = nvlist_get_number(limits, "flags");
2931e9ce60aSMariusz Zaborski 	(void)nvlist_get_number(limits, "operations");
294cdd6ea94SMariusz Zaborski 
295cdd6ea94SMariusz Zaborski 	/* Limits are consumed no need to free them. */
296cdd6ea94SMariusz Zaborski 	ret = cap_limit_set(chann, limits);
297cdd6ea94SMariusz Zaborski 	if (ret < 0)
298cdd6ea94SMariusz Zaborski 		goto out;
299cdd6ea94SMariusz Zaborski 
300cdd6ea94SMariusz Zaborski 	fa = fileargs_create(chann, flags);
301cdd6ea94SMariusz Zaborski 	if (fa == NULL)
302cdd6ea94SMariusz Zaborski 		goto out;
303cdd6ea94SMariusz Zaborski 
304cdd6ea94SMariusz Zaborski 	return (fa);
305cdd6ea94SMariusz Zaborski out:
306cdd6ea94SMariusz Zaborski 	serrno = errno;
307cdd6ea94SMariusz Zaborski 	if (chann != NULL)
308cdd6ea94SMariusz Zaborski 		cap_close(chann);
309cdd6ea94SMariusz Zaborski 	errno = serrno;
310cdd6ea94SMariusz Zaborski 	return (NULL);
311cdd6ea94SMariusz Zaborski }
312cdd6ea94SMariusz Zaborski 
313cdd6ea94SMariusz Zaborski int
fileargs_open(fileargs_t * fa,const char * name)314cdd6ea94SMariusz Zaborski fileargs_open(fileargs_t *fa, const char *name)
315cdd6ea94SMariusz Zaborski {
316cdd6ea94SMariusz Zaborski 	int fd;
317cdd6ea94SMariusz Zaborski 	nvlist_t *nvl;
318cdd6ea94SMariusz Zaborski 	char *cmd;
319cdd6ea94SMariusz Zaborski 
320cdd6ea94SMariusz Zaborski 	assert(fa != NULL);
321cdd6ea94SMariusz Zaborski 	assert(fa->fa_magic == FILEARGS_MAGIC);
322cdd6ea94SMariusz Zaborski 
323cdd6ea94SMariusz Zaborski 	if (name == NULL) {
324cdd6ea94SMariusz Zaborski 		errno = EINVAL;
325cdd6ea94SMariusz Zaborski 		return (-1);
326cdd6ea94SMariusz Zaborski 	}
327cdd6ea94SMariusz Zaborski 
328cdd6ea94SMariusz Zaborski 	if (fa->fa_chann == NULL) {
329cdd6ea94SMariusz Zaborski 		errno = ENOTCAPABLE;
330cdd6ea94SMariusz Zaborski 		return (-1);
331cdd6ea94SMariusz Zaborski 	}
332cdd6ea94SMariusz Zaborski 
3337b558caeSEd Maste 	fd = fileargs_get_fd_cache(fa, name);
334cdd6ea94SMariusz Zaborski 	if (fd != -1)
335cdd6ea94SMariusz Zaborski 		return (fd);
336cdd6ea94SMariusz Zaborski 
3377b558caeSEd Maste 	nvl = fileargs_fetch(fa, name, "open");
338cdd6ea94SMariusz Zaborski 	if (nvl == NULL)
339cdd6ea94SMariusz Zaborski 		return (-1);
340cdd6ea94SMariusz Zaborski 
341cdd6ea94SMariusz Zaborski 	fd = nvlist_take_descriptor(nvl, "fd");
342cdd6ea94SMariusz Zaborski 	cmd = nvlist_take_string(nvl, "cmd");
343cdd6ea94SMariusz Zaborski 	if (strcmp(cmd, "cache") == 0)
344cdd6ea94SMariusz Zaborski 		fileargs_set_cache(fa, nvl);
345cdd6ea94SMariusz Zaborski 	else
346cdd6ea94SMariusz Zaborski 		nvlist_destroy(nvl);
347cdd6ea94SMariusz Zaborski 	free(cmd);
348cdd6ea94SMariusz Zaborski 
349cdd6ea94SMariusz Zaborski 	return (fd);
350cdd6ea94SMariusz Zaborski }
351cdd6ea94SMariusz Zaborski 
352cdd6ea94SMariusz Zaborski FILE *
fileargs_fopen(fileargs_t * fa,const char * name,const char * mode)353cdd6ea94SMariusz Zaborski fileargs_fopen(fileargs_t *fa, const char *name, const char *mode)
354cdd6ea94SMariusz Zaborski {
355cdd6ea94SMariusz Zaborski 	int fd;
356cdd6ea94SMariusz Zaborski 
357cdd6ea94SMariusz Zaborski 	if ((fd = fileargs_open(fa, name)) < 0) {
358cdd6ea94SMariusz Zaborski 		return (NULL);
359cdd6ea94SMariusz Zaborski 	}
360cdd6ea94SMariusz Zaborski 
361cdd6ea94SMariusz Zaborski 	return (fdopen(fd, mode));
362cdd6ea94SMariusz Zaborski }
363cdd6ea94SMariusz Zaborski 
3647b558caeSEd Maste int
fileargs_lstat(fileargs_t * fa,const char * name,struct stat * sb)3657b558caeSEd Maste fileargs_lstat(fileargs_t *fa, const char *name, struct stat *sb)
3667b558caeSEd Maste {
3677b558caeSEd Maste 	nvlist_t *nvl;
3687b558caeSEd Maste 	const void *buf;
3697b558caeSEd Maste 	size_t size;
3707b558caeSEd Maste 	char *cmd;
3717b558caeSEd Maste 
3727b558caeSEd Maste 	assert(fa != NULL);
3737b558caeSEd Maste 	assert(fa->fa_magic == FILEARGS_MAGIC);
3747b558caeSEd Maste 
3757b558caeSEd Maste 	if (name == NULL) {
3767b558caeSEd Maste 		errno = EINVAL;
3777b558caeSEd Maste 		return (-1);
3787b558caeSEd Maste 	}
3797b558caeSEd Maste 
3807b558caeSEd Maste 	if (sb == NULL) {
3817b558caeSEd Maste 		errno = EFAULT;
3827b558caeSEd Maste 		return (-1);
3837b558caeSEd Maste 	}
3847b558caeSEd Maste 
3857b558caeSEd Maste 	if (fa->fa_chann == NULL) {
3867b558caeSEd Maste 		errno = ENOTCAPABLE;
3877b558caeSEd Maste 		return (-1);
3887b558caeSEd Maste 	}
3897b558caeSEd Maste 
3907b558caeSEd Maste 	if (fileargs_get_lstat_cache(fa, name, sb) != -1)
3917b558caeSEd Maste 		return (0);
3927b558caeSEd Maste 
3937b558caeSEd Maste 	nvl = fileargs_fetch(fa, name, "lstat");
3947b558caeSEd Maste 	if (nvl == NULL)
3957b558caeSEd Maste 		return (-1);
3967b558caeSEd Maste 
3977b558caeSEd Maste 	buf = nvlist_get_binary(nvl, "stat", &size);
3987b558caeSEd Maste 	assert(size == sizeof(*sb));
3997b558caeSEd Maste 	memcpy(sb, buf, size);
4007b558caeSEd Maste 
4017b558caeSEd Maste 	cmd = nvlist_take_string(nvl, "cmd");
4027b558caeSEd Maste 	if (strcmp(cmd, "cache") == 0)
4037b558caeSEd Maste 		fileargs_set_cache(fa, nvl);
4047b558caeSEd Maste 	else
4057b558caeSEd Maste 		nvlist_destroy(nvl);
4067b558caeSEd Maste 	free(cmd);
4077b558caeSEd Maste 
4087b558caeSEd Maste 	return (0);
4097b558caeSEd Maste }
4107b558caeSEd Maste 
411dcdad299SMariusz Zaborski char *
fileargs_realpath(fileargs_t * fa,const char * pathname,char * reserved_path)412dcdad299SMariusz Zaborski fileargs_realpath(fileargs_t *fa, const char *pathname, char *reserved_path)
413dcdad299SMariusz Zaborski {
414dcdad299SMariusz Zaborski 	nvlist_t *nvl;
415dcdad299SMariusz Zaborski 	char *ret;
416dcdad299SMariusz Zaborski 
417dcdad299SMariusz Zaborski 	assert(fa != NULL);
418dcdad299SMariusz Zaborski 	assert(fa->fa_magic == FILEARGS_MAGIC);
419dcdad299SMariusz Zaborski 
420dcdad299SMariusz Zaborski 	if (pathname == NULL) {
421dcdad299SMariusz Zaborski 		errno = EINVAL;
422dcdad299SMariusz Zaborski 		return (NULL);
423dcdad299SMariusz Zaborski 	}
424dcdad299SMariusz Zaborski 
425dcdad299SMariusz Zaborski 	if (fa->fa_chann == NULL) {
426dcdad299SMariusz Zaborski 		errno = ENOTCAPABLE;
427dcdad299SMariusz Zaborski 		return (NULL);
428dcdad299SMariusz Zaborski 	}
429dcdad299SMariusz Zaborski 
430dcdad299SMariusz Zaborski 	nvl = fileargs_fetch(fa, pathname, "realpath");
431dcdad299SMariusz Zaborski 	if (nvl == NULL)
432dcdad299SMariusz Zaborski 		return (NULL);
433dcdad299SMariusz Zaborski 
434dcdad299SMariusz Zaborski 	if (reserved_path != NULL) {
435dcdad299SMariusz Zaborski 		ret = reserved_path;
436dcdad299SMariusz Zaborski 		strcpy(reserved_path,
437dcdad299SMariusz Zaborski 		    nvlist_get_string(nvl, "realpath"));
438dcdad299SMariusz Zaborski 	} else {
439dcdad299SMariusz Zaborski 		ret = nvlist_take_string(nvl, "realpath");
440dcdad299SMariusz Zaborski 	}
441dcdad299SMariusz Zaborski 	nvlist_destroy(nvl);
442dcdad299SMariusz Zaborski 
443dcdad299SMariusz Zaborski 	return (ret);
444dcdad299SMariusz Zaborski }
445dcdad299SMariusz Zaborski 
446cdd6ea94SMariusz Zaborski void
fileargs_free(fileargs_t * fa)447cdd6ea94SMariusz Zaborski fileargs_free(fileargs_t *fa)
448cdd6ea94SMariusz Zaborski {
449cdd6ea94SMariusz Zaborski 
450cdd6ea94SMariusz Zaborski 	if (fa == NULL)
451cdd6ea94SMariusz Zaborski 		return;
452cdd6ea94SMariusz Zaborski 
453cdd6ea94SMariusz Zaborski 	assert(fa->fa_magic == FILEARGS_MAGIC);
454cdd6ea94SMariusz Zaborski 
455cdd6ea94SMariusz Zaborski 	nvlist_destroy(fa->fa_cache);
456cdd6ea94SMariusz Zaborski 	if (fa->fa_chann != NULL) {
457cdd6ea94SMariusz Zaborski 		cap_close(fa->fa_chann);
458cdd6ea94SMariusz Zaborski 	}
459cdd6ea94SMariusz Zaborski 	explicit_bzero(&fa->fa_magic, sizeof(fa->fa_magic));
460cdd6ea94SMariusz Zaborski 	free(fa);
461cdd6ea94SMariusz Zaborski }
462cdd6ea94SMariusz Zaborski 
4634b3f7927SMariusz Zaborski cap_channel_t *
fileargs_unwrap(fileargs_t * fa,int * flags)4644b3f7927SMariusz Zaborski fileargs_unwrap(fileargs_t *fa, int *flags)
4654b3f7927SMariusz Zaborski {
4664b3f7927SMariusz Zaborski 	cap_channel_t *chan;
4674b3f7927SMariusz Zaborski 
4684b3f7927SMariusz Zaborski 	if (fa == NULL)
4694b3f7927SMariusz Zaborski 		return (NULL);
4704b3f7927SMariusz Zaborski 
4714b3f7927SMariusz Zaborski 	assert(fa->fa_magic == FILEARGS_MAGIC);
4724b3f7927SMariusz Zaborski 
4734b3f7927SMariusz Zaborski 	chan = fa->fa_chann;
4744b3f7927SMariusz Zaborski 	if (flags != NULL) {
4754b3f7927SMariusz Zaborski 		*flags = fa->fa_fdflags;
4764b3f7927SMariusz Zaborski 	}
4774b3f7927SMariusz Zaborski 
4784b3f7927SMariusz Zaborski 	nvlist_destroy(fa->fa_cache);
4794b3f7927SMariusz Zaborski 	explicit_bzero(&fa->fa_magic, sizeof(fa->fa_magic));
4804b3f7927SMariusz Zaborski 	free(fa);
4814b3f7927SMariusz Zaborski 
4824b3f7927SMariusz Zaborski 	return (chan);
4834b3f7927SMariusz Zaborski }
4844b3f7927SMariusz Zaborski 
4854b3f7927SMariusz Zaborski fileargs_t *
fileargs_wrap(cap_channel_t * chan,int fdflags)4864b3f7927SMariusz Zaborski fileargs_wrap(cap_channel_t *chan, int fdflags)
4874b3f7927SMariusz Zaborski {
4884b3f7927SMariusz Zaborski 
4894b3f7927SMariusz Zaborski 	if (chan == NULL) {
4904b3f7927SMariusz Zaborski 		return (NULL);
4914b3f7927SMariusz Zaborski 	}
4924b3f7927SMariusz Zaborski 
4934b3f7927SMariusz Zaborski 	return (fileargs_create(chan, fdflags));
4944b3f7927SMariusz Zaborski }
4954b3f7927SMariusz Zaborski 
496cdd6ea94SMariusz Zaborski /*
497cdd6ea94SMariusz Zaborski  * Service functions.
498cdd6ea94SMariusz Zaborski  */
499cdd6ea94SMariusz Zaborski 
500cdd6ea94SMariusz Zaborski static const char *lastname;
501cdd6ea94SMariusz Zaborski static void *cacheposition;
502cdd6ea94SMariusz Zaborski static bool allcached;
503cdd6ea94SMariusz Zaborski static const cap_rights_t *caprightsp;
504cdd6ea94SMariusz Zaborski static int capflags;
5057b558caeSEd Maste static int allowed_operations;
506cdd6ea94SMariusz Zaborski static mode_t capmode;
507cdd6ea94SMariusz Zaborski 
508cdd6ea94SMariusz Zaborski static int
open_file(const char * name)509cdd6ea94SMariusz Zaborski open_file(const char *name)
510cdd6ea94SMariusz Zaborski {
511cdd6ea94SMariusz Zaborski 	int fd, serrno;
512cdd6ea94SMariusz Zaborski 
513cdd6ea94SMariusz Zaborski 	if ((capflags & O_CREAT) == 0)
514cdd6ea94SMariusz Zaborski 		fd = open(name, capflags);
515cdd6ea94SMariusz Zaborski 	else
516cdd6ea94SMariusz Zaborski 		fd = open(name, capflags, capmode);
517cdd6ea94SMariusz Zaborski 	if (fd < 0)
518cdd6ea94SMariusz Zaborski 		return (-1);
519cdd6ea94SMariusz Zaborski 
520cdd6ea94SMariusz Zaborski 	if (caprightsp != NULL) {
52177ebcc05SMariusz Zaborski 		if (cap_rights_limit(fd, caprightsp) < 0 && errno != ENOSYS) {
522cdd6ea94SMariusz Zaborski 			serrno = errno;
523cdd6ea94SMariusz Zaborski 			close(fd);
524cdd6ea94SMariusz Zaborski 			errno = serrno;
525cdd6ea94SMariusz Zaborski 			return (-1);
526cdd6ea94SMariusz Zaborski 		}
527cdd6ea94SMariusz Zaborski 	}
528cdd6ea94SMariusz Zaborski 
529cdd6ea94SMariusz Zaborski 	return (fd);
530cdd6ea94SMariusz Zaborski }
531cdd6ea94SMariusz Zaborski 
532cdd6ea94SMariusz Zaborski static void
fileargs_add_cache(nvlist_t * nvlout,const nvlist_t * limits,const char * current_name)533cdd6ea94SMariusz Zaborski fileargs_add_cache(nvlist_t *nvlout, const nvlist_t *limits,
534c78e42e2SMark Johnston     const char *current_name)
535cdd6ea94SMariusz Zaborski {
536cdd6ea94SMariusz Zaborski 	int type, i, fd;
537cdd6ea94SMariusz Zaborski 	void *cookie;
538cdd6ea94SMariusz Zaborski 	nvlist_t *new;
539cdd6ea94SMariusz Zaborski 	const char *fname;
5407b558caeSEd Maste 	struct stat sb;
541cdd6ea94SMariusz Zaborski 
542cdd6ea94SMariusz Zaborski 	if ((capflags & O_CREAT) != 0) {
543cdd6ea94SMariusz Zaborski 		allcached = true;
544cdd6ea94SMariusz Zaborski 		return;
545cdd6ea94SMariusz Zaborski 	}
546cdd6ea94SMariusz Zaborski 
547cdd6ea94SMariusz Zaborski 	cookie = cacheposition;
548cdd6ea94SMariusz Zaborski 	for (i = 0; i < CACHE_SIZE + 1; i++) {
549cdd6ea94SMariusz Zaborski 		fname = nvlist_next(limits, &type, &cookie);
550cdd6ea94SMariusz Zaborski 		if (fname == NULL) {
551cdd6ea94SMariusz Zaborski 			cacheposition = NULL;
552cdd6ea94SMariusz Zaborski 			lastname = NULL;
553cdd6ea94SMariusz Zaborski 			allcached = true;
554cdd6ea94SMariusz Zaborski 			return;
555cdd6ea94SMariusz Zaborski 		}
556cdd6ea94SMariusz Zaborski 		/* We doing that to catch next element name. */
557cdd6ea94SMariusz Zaborski 		if (i == CACHE_SIZE) {
558cdd6ea94SMariusz Zaborski 			break;
559cdd6ea94SMariusz Zaborski 		}
560cdd6ea94SMariusz Zaborski 
5612b1d0c00SMariusz Zaborski 		if (type != NV_TYPE_NULL) {
5622b1d0c00SMariusz Zaborski 			i--;
5632b1d0c00SMariusz Zaborski 			continue;
5642b1d0c00SMariusz Zaborski 		}
5652b1d0c00SMariusz Zaborski 		if (current_name != NULL &&
5662b1d0c00SMariusz Zaborski 		    strcmp(fname, current_name) == 0) {
567c78e42e2SMark Johnston 			current_name = NULL;
568cdd6ea94SMariusz Zaborski 			i--;
569cdd6ea94SMariusz Zaborski 			continue;
570cdd6ea94SMariusz Zaborski 		}
571cdd6ea94SMariusz Zaborski 
5727b558caeSEd Maste 		new = nvlist_create(NV_FLAG_NO_UNIQUE);
5737b558caeSEd Maste 		if ((allowed_operations & FA_OPEN) != 0) {
574cdd6ea94SMariusz Zaborski 			fd = open_file(fname);
575cdd6ea94SMariusz Zaborski 			if (fd < 0) {
576cdd6ea94SMariusz Zaborski 				i--;
5777b558caeSEd Maste 				nvlist_destroy(new);
578cdd6ea94SMariusz Zaborski 				continue;
579cdd6ea94SMariusz Zaborski 			}
580cdd6ea94SMariusz Zaborski 			nvlist_move_descriptor(new, "fd", fd);
5817b558caeSEd Maste 		}
5827b558caeSEd Maste 		if ((allowed_operations & FA_LSTAT) != 0) {
5837b558caeSEd Maste 			if (lstat(fname, &sb) < 0) {
5847b558caeSEd Maste 				i--;
5857b558caeSEd Maste 				nvlist_destroy(new);
5867b558caeSEd Maste 				continue;
5877b558caeSEd Maste 			}
5887b558caeSEd Maste 			nvlist_add_binary(new, "stat", &sb, sizeof(sb));
5897b558caeSEd Maste 		}
5907b558caeSEd Maste 
591c78e42e2SMark Johnston 		nvlist_move_nvlist(nvlout, fname, new);
592cdd6ea94SMariusz Zaborski 	}
593cdd6ea94SMariusz Zaborski 	cacheposition = cookie;
594cdd6ea94SMariusz Zaborski 	lastname = fname;
595cdd6ea94SMariusz Zaborski }
596cdd6ea94SMariusz Zaborski 
597cdd6ea94SMariusz Zaborski static bool
fileargs_allowed(const nvlist_t * limits,const nvlist_t * request,int operation)5987b558caeSEd Maste fileargs_allowed(const nvlist_t *limits, const nvlist_t *request, int operation)
599cdd6ea94SMariusz Zaborski {
600cdd6ea94SMariusz Zaborski 	const char *name;
601cdd6ea94SMariusz Zaborski 
6027b558caeSEd Maste 	if ((allowed_operations & operation) == 0)
6037b558caeSEd Maste 		return (false);
6047b558caeSEd Maste 
605cdd6ea94SMariusz Zaborski 	name = dnvlist_get_string(request, "name", NULL);
606cdd6ea94SMariusz Zaborski 	if (name == NULL)
607cdd6ea94SMariusz Zaborski 		return (false);
608cdd6ea94SMariusz Zaborski 
609cdd6ea94SMariusz Zaborski 	/* Fast path. */
610cdd6ea94SMariusz Zaborski 	if (lastname != NULL && strcmp(name, lastname) == 0)
611cdd6ea94SMariusz Zaborski 		return (true);
612cdd6ea94SMariusz Zaborski 
613cdd6ea94SMariusz Zaborski 	if (!nvlist_exists_null(limits, name))
614cdd6ea94SMariusz Zaborski 		return (false);
615cdd6ea94SMariusz Zaborski 
616cdd6ea94SMariusz Zaborski 	return (true);
617cdd6ea94SMariusz Zaborski }
618cdd6ea94SMariusz Zaborski 
619cdd6ea94SMariusz Zaborski static int
fileargs_limit(const nvlist_t * oldlimits,const nvlist_t * newlimits)620cdd6ea94SMariusz Zaborski fileargs_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
621cdd6ea94SMariusz Zaborski {
622cdd6ea94SMariusz Zaborski 
623cdd6ea94SMariusz Zaborski 	if (oldlimits != NULL)
624cdd6ea94SMariusz Zaborski 		return (ENOTCAPABLE);
625cdd6ea94SMariusz Zaborski 
626cdd6ea94SMariusz Zaborski 	capflags = (int)dnvlist_get_number(newlimits, "flags", 0);
6277b558caeSEd Maste 	allowed_operations = (int)dnvlist_get_number(newlimits, "operations", 0);
628cdd6ea94SMariusz Zaborski 	if ((capflags & O_CREAT) != 0)
629cdd6ea94SMariusz Zaborski 		capmode = (mode_t)nvlist_get_number(newlimits, "mode");
630cdd6ea94SMariusz Zaborski 	else
631cdd6ea94SMariusz Zaborski 		capmode = 0;
632cdd6ea94SMariusz Zaborski 
633cdd6ea94SMariusz Zaborski 	caprightsp = dnvlist_get_binary(newlimits, "cap_rights", NULL, NULL, 0);
634cdd6ea94SMariusz Zaborski 
635cdd6ea94SMariusz Zaborski 	return (0);
636cdd6ea94SMariusz Zaborski }
637cdd6ea94SMariusz Zaborski 
638cdd6ea94SMariusz Zaborski static int
fileargs_command_lstat(const nvlist_t * limits,nvlist_t * nvlin,nvlist_t * nvlout)6397b558caeSEd Maste fileargs_command_lstat(const nvlist_t *limits, nvlist_t *nvlin,
6407b558caeSEd Maste     nvlist_t *nvlout)
6417b558caeSEd Maste {
642b6539d47SEd Maste 	int error;
6437b558caeSEd Maste 	const char *name;
6447b558caeSEd Maste 	struct stat sb;
6457b558caeSEd Maste 
6467b558caeSEd Maste 	if (limits == NULL)
6477b558caeSEd Maste 		return (ENOTCAPABLE);
6487b558caeSEd Maste 
6497b558caeSEd Maste 	if (!fileargs_allowed(limits, nvlin, FA_LSTAT))
6507b558caeSEd Maste 		return (ENOTCAPABLE);
6517b558caeSEd Maste 
6527b558caeSEd Maste 	name = nvlist_get_string(nvlin, "name");
6537b558caeSEd Maste 
654b6539d47SEd Maste 	error = lstat(name, &sb);
655151744cfSEd Maste 	if (error < 0)
6567b558caeSEd Maste 		return (errno);
6577b558caeSEd Maste 
6587b558caeSEd Maste 	if (!allcached && (lastname == NULL ||
6597b558caeSEd Maste 	    strcmp(name, lastname) == 0)) {
6607b558caeSEd Maste 		nvlist_add_string(nvlout, "cmd", "cache");
6617b558caeSEd Maste 		fileargs_add_cache(nvlout, limits, name);
6627b558caeSEd Maste 	} else {
6637b558caeSEd Maste 		nvlist_add_string(nvlout, "cmd", "lstat");
6647b558caeSEd Maste 	}
6657b558caeSEd Maste 	nvlist_add_binary(nvlout, "stat", &sb, sizeof(sb));
6667b558caeSEd Maste 	return (0);
6677b558caeSEd Maste }
6687b558caeSEd Maste 
6697b558caeSEd Maste static int
fileargs_command_realpath(const nvlist_t * limits,nvlist_t * nvlin,nvlist_t * nvlout)670dcdad299SMariusz Zaborski fileargs_command_realpath(const nvlist_t *limits, nvlist_t *nvlin,
671dcdad299SMariusz Zaborski     nvlist_t *nvlout)
672dcdad299SMariusz Zaborski {
673dcdad299SMariusz Zaborski 	const char *pathname;
674dcdad299SMariusz Zaborski 	char *resolvedpath;
675dcdad299SMariusz Zaborski 
676dcdad299SMariusz Zaborski 	if (limits == NULL)
677dcdad299SMariusz Zaborski 		return (ENOTCAPABLE);
678dcdad299SMariusz Zaborski 
679dcdad299SMariusz Zaborski 	if (!fileargs_allowed(limits, nvlin, FA_REALPATH))
680dcdad299SMariusz Zaborski 		return (ENOTCAPABLE);
681dcdad299SMariusz Zaborski 
682dcdad299SMariusz Zaborski 	pathname = nvlist_get_string(nvlin, "name");
683dcdad299SMariusz Zaborski 	resolvedpath = realpath(pathname, NULL);
684dcdad299SMariusz Zaborski 	if (resolvedpath == NULL)
685dcdad299SMariusz Zaborski 		return (errno);
686dcdad299SMariusz Zaborski 
687dcdad299SMariusz Zaborski 	nvlist_move_string(nvlout, "realpath", resolvedpath);
688dcdad299SMariusz Zaborski 	return (0);
689dcdad299SMariusz Zaborski }
690dcdad299SMariusz Zaborski 
691dcdad299SMariusz Zaborski static int
fileargs_command_open(const nvlist_t * limits,nvlist_t * nvlin,nvlist_t * nvlout)692cdd6ea94SMariusz Zaborski fileargs_command_open(const nvlist_t *limits, nvlist_t *nvlin,
693cdd6ea94SMariusz Zaborski     nvlist_t *nvlout)
694cdd6ea94SMariusz Zaborski {
695cdd6ea94SMariusz Zaborski 	int fd;
696cdd6ea94SMariusz Zaborski 	const char *name;
697cdd6ea94SMariusz Zaborski 
698cdd6ea94SMariusz Zaborski 	if (limits == NULL)
699cdd6ea94SMariusz Zaborski 		return (ENOTCAPABLE);
700cdd6ea94SMariusz Zaborski 
7017b558caeSEd Maste 	if (!fileargs_allowed(limits, nvlin, FA_OPEN))
702cdd6ea94SMariusz Zaborski 		return (ENOTCAPABLE);
703cdd6ea94SMariusz Zaborski 
704cdd6ea94SMariusz Zaborski 	name = nvlist_get_string(nvlin, "name");
705cdd6ea94SMariusz Zaborski 
706cdd6ea94SMariusz Zaborski 	fd = open_file(name);
707cdd6ea94SMariusz Zaborski 	if (fd < 0)
708cdd6ea94SMariusz Zaborski 		return (errno);
709cdd6ea94SMariusz Zaborski 
710cdd6ea94SMariusz Zaborski 	if (!allcached && (lastname == NULL ||
711cdd6ea94SMariusz Zaborski 	    strcmp(name, lastname) == 0)) {
712cdd6ea94SMariusz Zaborski 		nvlist_add_string(nvlout, "cmd", "cache");
713cdd6ea94SMariusz Zaborski 		fileargs_add_cache(nvlout, limits, name);
714cdd6ea94SMariusz Zaborski 	} else {
715cdd6ea94SMariusz Zaborski 		nvlist_add_string(nvlout, "cmd", "open");
716cdd6ea94SMariusz Zaborski 	}
717cdd6ea94SMariusz Zaborski 	nvlist_move_descriptor(nvlout, "fd", fd);
718cdd6ea94SMariusz Zaborski 	return (0);
719cdd6ea94SMariusz Zaborski }
720cdd6ea94SMariusz Zaborski 
721cdd6ea94SMariusz Zaborski static int
fileargs_command(const char * cmd,const nvlist_t * limits,nvlist_t * nvlin,nvlist_t * nvlout)722cdd6ea94SMariusz Zaborski fileargs_command(const char *cmd, const nvlist_t *limits,
723cdd6ea94SMariusz Zaborski     nvlist_t *nvlin, nvlist_t *nvlout)
724cdd6ea94SMariusz Zaborski {
725cdd6ea94SMariusz Zaborski 
726cdd6ea94SMariusz Zaborski 	if (strcmp(cmd, "open") == 0)
727cdd6ea94SMariusz Zaborski 		return (fileargs_command_open(limits, nvlin, nvlout));
7287b558caeSEd Maste 	if (strcmp(cmd, "lstat") == 0)
7297b558caeSEd Maste 		return (fileargs_command_lstat(limits, nvlin, nvlout));
730dcdad299SMariusz Zaborski 	if (strcmp(cmd, "realpath") == 0)
731dcdad299SMariusz Zaborski 		return (fileargs_command_realpath(limits, nvlin, nvlout));
7327b558caeSEd Maste 
733cdd6ea94SMariusz Zaborski 	return (EINVAL);
734cdd6ea94SMariusz Zaborski }
735cdd6ea94SMariusz Zaborski 
736cdd6ea94SMariusz Zaborski CREATE_SERVICE("system.fileargs", fileargs_limit, fileargs_command,
737cdd6ea94SMariusz Zaborski     CASPER_SERVICE_FD | CASPER_SERVICE_STDIO | CASPER_SERVICE_NO_UNIQ_LIMITS);
738