1 /*- 2 * Copyright (c) 2018, Juniper Networks, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 14 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 15 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 16 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 17 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 19 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 #include <sys/cdefs.h> 26 __FBSDID("$FreeBSD$"); 27 28 #include <stdlib.h> 29 #include <sysexits.h> 30 #include <unistd.h> 31 #include <paths.h> 32 #include <err.h> 33 #include <syslog.h> 34 #include <libsecureboot.h> 35 #include <libveriexec.h> 36 #include <sys/types.h> 37 38 #include "veriexec.h" 39 40 /* Globals that are shared with manifest_parser.c */ 41 int dev_fd = -1; 42 int ForceFlags = 0; 43 int Verbose = 0; 44 int VeriexecVersion = 0; 45 const char *Cdir = NULL; 46 47 /*! 48 * @brief Print help message describing program's usage 49 * @param void 50 * @return always returns code 0 51 */ 52 static int 53 veriexec_usage(void) 54 { 55 printf("%s", 56 "Usage:\tveriexec [-h] [-i state] [-C] [-xv state|verbosity] [path]\n"); 57 58 return (0); 59 } 60 61 /*! 62 * @brief Load a veriexec manifest 63 * @param manifest Pointer to the location of the manifest file 64 * @retval the error code returned from the parser 65 */ 66 static int 67 veriexec_load(const char *manifest) 68 { 69 unsigned char *content; 70 int rc; 71 72 content = verify_signed(manifest, VEF_VERBOSE); 73 if (!content) 74 errx(EX_USAGE, "cannot verify %s", manifest); 75 if (manifest_open(manifest, (const char *)content)) { 76 rc = yyparse(); 77 } else { 78 err(EX_NOINPUT, "cannot load %s", manifest); 79 } 80 free(content); 81 return (rc); 82 } 83 84 /*! 85 * @brief Get the veriexec state for the supplied argument 86 * @param arg_text String containing the argument to be processed 87 * @retval The veriexec state number for the specified argument 88 */ 89 static uint32_t 90 veriexec_state_query(const char *arg_text) 91 { 92 uint32_t state = 0; 93 unsigned long len; 94 95 len = strlen(arg_text); 96 97 if (strncmp(arg_text, "active", len) == 0) 98 state |= VERIEXEC_STATE_ACTIVE; 99 else if (strncmp(arg_text, "enforce", len) == 0) 100 state |= VERIEXEC_STATE_ENFORCE; 101 if (strncmp(arg_text, "loaded", len) == 0) 102 state |= VERIEXEC_STATE_LOADED; 103 if (strncmp(arg_text, "locked", len) == 0) 104 state |= VERIEXEC_STATE_LOCKED; 105 if (state == 0 || __bitcount(state) > 1) 106 errx(EX_USAGE, "Unknown state \'%s\'", arg_text); 107 108 return (state); 109 } 110 111 /*! 112 * @brief Get the veriexec command state for the supplied argument 113 * @param arg_text String containing the argument to be processed 114 * @retval The veriexec command state for the specified argument 115 */ 116 static uint32_t 117 veriexec_state_modify(const char *arg_text) 118 { 119 uint32_t state = 0; 120 unsigned long len; 121 122 len = strlen(arg_text); 123 124 if (strncmp(arg_text, "active", len) == 0) 125 state = VERIEXEC_ACTIVE; 126 else if (strncmp(arg_text, "enforce", len) == 0) 127 state = VERIEXEC_ENFORCE; 128 else if (strncmp(arg_text, "getstate", len) == 0) 129 state = VERIEXEC_GETSTATE; 130 else if (strncmp(arg_text, "lock", len) == 0) 131 state = VERIEXEC_LOCK; 132 else 133 errx(EX_USAGE, "Unknown command \'%s\'", arg_text); 134 135 return (state); 136 } 137 138 int 139 main(int argc, char *argv[]) 140 { 141 long long converted_int; 142 uint32_t state; 143 char c; 144 int x; 145 146 if (argc < 2) 147 return (veriexec_usage()); 148 149 dev_fd = open(_PATH_DEV_VERIEXEC, O_WRONLY, 0); 150 151 while ((c = getopt(argc, argv, "hC:i:Sxvz:")) != -1) { 152 switch (c) { 153 case 'h': 154 /* Print usage info */ 155 156 return (veriexec_usage()); 157 case 'C': 158 /* Get the provided directory argument */ 159 160 Cdir = optarg; 161 break; 162 case 'i': 163 /* Query the current state */ 164 165 if (dev_fd < 0) { 166 err(EX_UNAVAILABLE, "cannot open veriexec"); 167 } 168 if (ioctl(dev_fd, VERIEXEC_GETSTATE, &x)) { 169 err(EX_UNAVAILABLE, 170 "Cannot get veriexec state"); 171 } 172 173 state = veriexec_state_query(optarg); 174 175 exit((x & state) == 0); 176 break; 177 case 'S': 178 /* Strictly enforce certificate validity */ 179 ve_enforce_validity_set(1); 180 break; 181 case 'v': 182 /* Increase the verbosity */ 183 184 Verbose++; 185 break; 186 case 'x': 187 /* Check veriexec paths */ 188 189 /* 190 * -x says all other args are paths to check. 191 */ 192 for (x = EX_OK; optind < argc; optind++) { 193 if (veriexec_check_path(argv[optind])) { 194 warn("%s", argv[optind]); 195 x = 2; 196 } 197 } 198 exit(x); 199 break; 200 case 'z': 201 /* Modify the state */ 202 203 if (strncmp(optarg, "debug", strlen(optarg)) == 0) { 204 const char *error; 205 206 if (optind >= argc) 207 errx(EX_USAGE, 208 "Missing mac_veriexec verbosity level \'N\', veriexec -z debug N, where N is \'off\' or the value 0 or greater"); 209 210 if (strncmp(argv[optind], "off", strlen(argv[optind])) == 0) { 211 state = VERIEXEC_DEBUG_OFF; 212 x = 0; 213 } else { 214 state = VERIEXEC_DEBUG_ON; 215 216 converted_int = strtonum(argv[optind], 0, INT_MAX, &error); 217 218 if (error != NULL) 219 errx(EX_USAGE, "Conversion error for argument \'%s\' : %s", 220 argv[optind], error); 221 222 x = (int) converted_int; 223 224 225 if (x == 0) 226 state = VERIEXEC_DEBUG_OFF; 227 } 228 } else 229 state = veriexec_state_modify(optarg); 230 231 if (dev_fd < 0) 232 err(EX_UNAVAILABLE, "Cannot open veriexec"); 233 if (ioctl(dev_fd, state, &x)) 234 err(EX_UNAVAILABLE, "Cannot %s veriexec", optarg); 235 236 if (state == VERIEXEC_DEBUG_ON || state == VERIEXEC_DEBUG_OFF) 237 printf("mac_veriexec debug verbosity level: %d\n", x); 238 else if (state == VERIEXEC_GETSTATE) 239 printf("Veriexec state (octal) : %#o\n", x); 240 241 exit(EX_OK); 242 break; 243 default: 244 245 /* Missing argument, print usage info.*/ 246 veriexec_usage(); 247 exit(EX_USAGE); 248 break; 249 } 250 } 251 252 if (Verbose) 253 printf("Verbosity level : %d\n", Verbose); 254 255 if (dev_fd < 0) 256 err(EX_UNAVAILABLE, "Cannot open veriexec"); 257 258 openlog(getprogname(), LOG_PID, LOG_AUTH); 259 if (ve_trust_init() < 1) 260 errx(EX_OSFILE, "cannot initialize trust store"); 261 #ifdef VERIEXEC_GETVERSION 262 if (ioctl(dev_fd, VERIEXEC_GETVERSION, &VeriexecVersion)) { 263 VeriexecVersion = 0; /* unknown */ 264 } 265 #endif 266 267 for (; optind < argc; optind++) { 268 if (veriexec_load(argv[optind])) { 269 err(EX_DATAERR, "cannot load %s", argv[optind]); 270 } 271 } 272 exit(EX_OK); 273 } 274