1/*
2 * $FreeBSD$
3 *
4 * Copyright (c) 2011, 2012, 2013, 2015, Juniper Networks, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30#include <sys/types.h>
31#include <sys/errno.h>
32#include <sys/mac.h>
33#include <sys/stat.h>
34
35#include <stdio.h>
36#include <string.h>
37#include <unistd.h>
38#include <fcntl.h>
39#include <paths.h>
40
41#include <security/mac_veriexec/mac_veriexec.h>
42
43#include "libveriexec.h"
44
45
46static int
47check_fd_mode(int fd, unsigned int mask)
48{
49	struct stat st;
50
51	if (fstat(fd, &st) < 0)
52		return errno;
53
54	if ((st.st_mode & mask) == 0)
55		return EAUTH;
56
57	return 0;
58}
59
60int
61veriexec_check_fd_mode(int fd, unsigned int mask)
62{
63	int error;
64
65	if (fd < 0) {
66		errno = EINVAL;
67		return -1;
68	}
69
70	error = mac_syscall(MAC_VERIEXEC_NAME, MAC_VERIEXEC_CHECK_FD_SYSCALL,
71	    (void *)(intptr_t)fd);
72	if (error == -1) {
73		switch (errno) {
74		case ENOSYS:	/* veriexec not loaded */
75			error = 0;	/* ignore */
76			break;
77		}
78	}
79	if (mask && error == 0)
80	    error = check_fd_mode(fd, mask);
81
82	return (error);
83}
84
85int
86veriexec_check_path_mode(const char *file, unsigned int mask)
87{
88	int error;
89
90	if (!file) {
91		errno = EINVAL;
92		return -1;
93	}
94
95	if (mask) {
96		int fd;
97
98		if ((fd = open(file, O_RDONLY)) < 0)
99			return errno;
100
101		error = veriexec_check_fd_mode(fd, mask);
102		close(fd);
103		return error;
104	}
105
106	error = mac_syscall(MAC_VERIEXEC_NAME, MAC_VERIEXEC_CHECK_PATH_SYSCALL,
107	    __DECONST(void *, file));
108	if (error == -1) {
109		switch (errno) {
110		case ENOSYS:	/* veriexec not loaded */
111			error = 0;	/* ignore */
112			break;
113		}
114	}
115	return (error);
116}
117
118int
119veriexec_check_fd(int fd)
120{
121	return veriexec_check_fd_mode(fd, 0);
122}
123
124int
125veriexec_check_path(const char *file)
126{
127	return veriexec_check_path_mode(file, 0);
128}
129
130#if defined(MAIN) || defined(UNIT_TEST)
131int
132main(int argc __unused, char *argv[] __unused)
133{
134	int error;
135	int rc = 0;
136
137	while (*++argv) {
138		error = veriexec_check_path(*argv);
139		if (error == -1) {
140			rc = 1;
141			warn("%s", *argv);
142		}
143	}
144	exit(rc);
145}
146#endif
147