]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/binmiscctl/binmiscctl.c
Bump __FreeBSD_version for bus resource API change
[FreeBSD/FreeBSD.git] / usr.sbin / binmiscctl / binmiscctl.c
1 /*-
2  * Copyright (c) 2013 Stacey D. Son
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27
28 #include <sys/types.h>
29 #include <sys/imgact_binmisc.h>
30 #include <sys/linker.h>
31 #include <sys/module.h>
32 #include <sys/sysctl.h>
33
34 #include <ctype.h>
35 #include <errno.h>
36 #include <getopt.h>
37 #include <stdio.h>
38 #include <stdarg.h>
39 #include <stdint.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 enum cmd {
44         CMD_ADD = 0,
45         CMD_REMOVE,
46         CMD_DISABLE,
47         CMD_ENABLE,
48         CMD_LOOKUP,
49         CMD_LIST,
50 };
51
52 extern char *__progname;
53
54 typedef int (*cmd_func_t)(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
55
56 int add_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
57 int name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
58 int noname_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
59
60 static const struct {
61         const int token;
62         const char *name;
63         cmd_func_t func;
64         const char *desc;
65         const char *args;
66 } cmds[] = {
67         {
68                 CMD_ADD,
69                 "add",
70                 add_cmd,
71                 "Add a new binary image activator (requires 'root' privilege)",
72                 "<name> --interpreter <path_and_arguments> \\\n"
73                 "\t\t--magic <magic_bytes> [--mask <mask_bytes>] \\\n"
74                 "\t\t--size <magic_size> [--offset <magic_offset>] \\\n"
75                 "\t\t[--set-enabled] \\\n"
76                 "\t\t[--pre-open]"
77         },
78         {
79                 CMD_REMOVE,
80                 "remove",
81                 name_cmd,
82                 "Remove a binary image activator (requires 'root' privilege)",
83                 "<name>"
84         },
85         {
86                 CMD_DISABLE,
87                 "disable",
88                 name_cmd,
89                 "Disable a binary image activator (requires 'root' privilege)",
90                 "<name>"
91         },
92         {
93                 CMD_ENABLE,
94                 "enable",
95                 name_cmd,
96                 "Enable a binary image activator (requires 'root' privilege)",
97                 "<name>"
98         },
99         {
100                 CMD_LOOKUP,
101                 "lookup",
102                 name_cmd,
103                 "Lookup a binary image activator",
104                 "<name>"
105         },
106         {
107                 CMD_LIST,
108                 "list",
109                 noname_cmd,
110                 "List all the binary image activators",
111                 ""
112         },
113 };
114
115 static const struct option
116 add_opts[] = {
117         { "set-enabled",        no_argument,            NULL,   'e' },
118         { "interpreter",        required_argument,      NULL,   'i' },
119         { "mask",               required_argument,      NULL,   'M' },
120         { "magic",              required_argument,      NULL,   'm' },
121         { "offset",             required_argument,      NULL,   'o' },
122         { "size",               required_argument,      NULL,   's' },
123         { "pre-open",           no_argument,            NULL,   'p' },
124         { NULL,                 0,                      NULL,   0   }
125 };
126
127 static char const *cmd_sysctl_name[] = {
128         IBE_SYSCTL_NAME_ADD,
129         IBE_SYSCTL_NAME_REMOVE,
130         IBE_SYSCTL_NAME_DISABLE,
131         IBE_SYSCTL_NAME_ENABLE,
132         IBE_SYSCTL_NAME_LOOKUP,
133         IBE_SYSCTL_NAME_LIST
134 };
135
136 static void __dead2
137 usage(const char *format, ...)
138 {
139         va_list args;
140         size_t i;
141         int error = 0;
142
143         va_start(args, format);
144         if (format) {
145                 vfprintf(stderr, format, args);
146                 error = -1;
147         }
148         va_end(args);
149         fprintf(stderr, "\n");
150         fprintf(stderr, "usage: %s command [args...]\n\n", __progname);
151
152         for(i = 0; i < nitems(cmds); i++) {
153                 fprintf(stderr, "%s:\n", cmds[i].desc);
154                 fprintf(stderr, "\t%s %s %s\n\n", __progname, cmds[i].name,
155                     cmds[i].args);
156         }
157
158         exit (error);
159 }
160
161 static void __dead2
162 fatal(const char *format, ...)
163 {
164         va_list args;
165
166         va_start(args, format);
167         if (format)
168                 vfprintf(stderr, format, args);
169         fprintf(stderr, "\n");
170
171         exit(-1);
172 }
173
174 static void
175 getoptstr(char *str, size_t size, const char *argname)
176 {
177         if (strlen(optarg) > size)
178                 usage("'%s' too large", argname);
179         strlcpy(str, optarg, size);
180 }
181
182 static void
183 printxbe(ximgact_binmisc_entry_t *xbe)
184 {
185         uint32_t i, flags = xbe->xbe_flags;
186
187         if (xbe->xbe_version != IBE_VERSION) {
188                 fprintf(stderr, "Error: XBE version mismatch\n");
189                 return;
190         }
191
192         printf("name: %s\n", xbe->xbe_name);
193         printf("interpreter: %s\n", xbe->xbe_interpreter);
194         printf("flags: %s%s%s\n", (flags & IBF_ENABLED) ? "ENABLED " : "",
195             (flags & IBF_USE_MASK) ? "USE_MASK " : "",
196             (flags & IBF_PRE_OPEN) ? "PRE_OPEN " : "");
197         printf("magic size: %u\n", xbe->xbe_msize);
198         printf("magic offset: %u\n", xbe->xbe_moffset);
199
200         printf("magic: ");
201         for(i = 0; i < xbe->xbe_msize;  i++) {
202                 if (i && !(i % 12))
203                         printf("\n       ");
204                 else
205                         if (i && !(i % 4))
206                                 printf(" ");
207                 printf("0x%02x ", xbe->xbe_magic[i]);
208         }
209         printf("\n");
210
211         if (flags & IBF_USE_MASK) {
212                 printf("mask:  ");
213                 for(i = 0; i < xbe->xbe_msize;  i++) {
214                         if (i && !(i % 12))
215                                 printf("\n       ");
216                         else
217                                 if (i && !(i % 4))
218                                         printf(" ");
219                         printf("0x%02x ", xbe->xbe_mask[i]);
220                 }
221                 printf("\n");
222         }
223
224         printf("\n");
225 }
226
227 static int
228 demux_cmd(__unused int argc, char *const argv[])
229 {
230         size_t i;
231
232         optind = 1;
233         optreset = 1;
234
235         for(i = 0; i < nitems(cmds); i++) {
236                 if (!strcasecmp(cmds[i].name, argv[0])) {
237                         return (i);
238                 }
239         }
240
241         /* Unknown command */
242         return (-1);
243 }
244
245 static int
246 strlit2bin_cpy(uint8_t *d, char *s, size_t size)
247 {
248         int c;
249         size_t cnt = 0;
250
251         while((c = *s++) != '\0') {
252                 if (c == '\\') {
253                         /* Do '\' escapes. */
254                         switch (*s) {
255                         case '\\':
256                                 *d++ = '\\';
257                                 break;
258
259                         case 'x':
260                                 s++;
261                                 c = toupper(*s++);
262                                 *d = (c - (isdigit(c) ? '0' : ('A' - 10))) << 4;
263                                 c = toupper(*s++);
264                                 *d++ |= c - (isdigit(c) ? '0' : ('A' - 10));
265                                 break;
266
267                         default:
268                                 return (-1);
269                         }
270                 } else
271                         *d++ = c;
272
273                 if (++cnt > size)
274                         return (-1);
275         }
276
277         return (cnt);
278 }
279
280 int
281 add_cmd(__unused int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
282 {
283         int ch;
284         char *magic = NULL, *mask = NULL;
285         int sz;
286
287         if (argc == 0)
288                 usage("Required argument missing\n");
289         if (strlen(argv[0]) > IBE_NAME_MAX)
290                 usage("'%s' string length longer than IBE_NAME_MAX (%d)",
291                     IBE_NAME_MAX);
292         strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
293
294         while ((ch = getopt_long(argc, argv, "epi:m:M:o:s:", add_opts, NULL))
295             != -1) {
296
297                 switch(ch) {
298                 case 'i':
299                         getoptstr(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX,
300                             "interpreter");
301                         break;
302
303                 case 'm':
304                         free(magic);
305                         magic = strdup(optarg);
306                         break;
307
308                 case 'M':
309                         free(mask);
310                         mask = strdup(optarg);
311                         xbe->xbe_flags |= IBF_USE_MASK;
312                         break;
313
314                 case 'e':
315                         xbe->xbe_flags |= IBF_ENABLED;
316                         break;
317
318                 case 'o':
319                         xbe->xbe_moffset = atol(optarg);
320                         break;
321
322                 case 's':
323                         xbe->xbe_msize = atol(optarg);
324                         if (xbe->xbe_msize == 0 ||
325                             xbe->xbe_msize > IBE_MAGIC_MAX)
326                                 usage("Error: Not valid '--size' value. "
327                                     "(Must be > 0 and < %u.)\n",
328                                     xbe->xbe_msize);
329                         break;
330
331                 case 'p':
332                         xbe->xbe_flags |= IBF_PRE_OPEN;
333                         break;
334
335                 default:
336                         usage("Unknown argument: '%c'", ch);
337                 }
338         }
339
340         if (xbe->xbe_msize == 0) {
341                 if (NULL != magic)
342                         free(magic);
343                 if (NULL != mask)
344                         free(mask);
345                 usage("Error: Missing '--size' argument");
346         }
347
348         if (NULL != magic) {
349                 if (xbe->xbe_msize == 0) {
350                         if (magic)
351                                 free(magic);
352                         if (mask)
353                                 free(mask);
354                         usage("Error: Missing magic size argument");
355                 }
356                 sz = strlit2bin_cpy(xbe->xbe_magic, magic, IBE_MAGIC_MAX);
357                 free(magic);
358                 if (sz == -1 || (uint32_t)sz != xbe->xbe_msize) {
359                         if (mask)
360                                 free(mask);
361                         usage("Error: invalid magic argument");
362                 }
363                 if (mask) {
364                         sz = strlit2bin_cpy(xbe->xbe_mask, mask, IBE_MAGIC_MAX);
365                         free(mask);
366                         if (sz == -1 || (uint32_t)sz != xbe->xbe_msize)
367                                 usage("Error: invalid mask argument");
368                 }
369         } else {
370                 if (mask)
371                         free(mask);
372                 usage("Error: Missing magic argument");
373         }
374
375         if (!strnlen(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX)) {
376                 usage("Error: Missing 'interpreter' argument");
377         }
378
379         return (0);
380 }
381
382 int
383 name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
384 {
385         if (argc == 0)
386                 usage("Required argument missing\n");
387         if (strlen(argv[0]) > IBE_NAME_MAX)
388                 usage("'%s' string length longer than IBE_NAME_MAX (%d)",
389                     IBE_NAME_MAX);
390         strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
391
392         return (0);
393 }
394
395 int
396 noname_cmd(__unused int argc, __unused char *argv[],
397     __unused ximgact_binmisc_entry_t *xbe)
398 {
399
400         return (0);
401 }
402
403 int
404 main(int argc, char **argv)
405 {
406         int error = 0, cmd = -1;
407         ximgact_binmisc_entry_t xbe_in, *xbe_inp = NULL;
408         ximgact_binmisc_entry_t xbe_out, *xbe_outp = NULL;
409         size_t xbe_in_sz = 0;
410         size_t xbe_out_sz = 0, *xbe_out_szp = NULL;
411         uint32_t i;
412
413         if (modfind(KMOD_NAME) == -1) {
414                 if (kldload(KMOD_NAME) == -1)
415                         fatal("Can't load %s kernel module: %s",
416                             KMOD_NAME, strerror(errno));
417         }
418
419         bzero(&xbe_in, sizeof(xbe_in));
420         bzero(&xbe_out, sizeof(xbe_out));
421         xbe_in.xbe_version = IBE_VERSION;
422
423         if (argc < 2)
424                 usage("Error: requires at least one argument");
425
426         argc--, argv++;
427         cmd = demux_cmd(argc, argv);
428         if (cmd < 0)
429                 usage("Error: Unknown command \"%s\"", argv[0]);
430         argc--, argv++;
431
432         error = (*cmds[cmd].func)(argc, argv, &xbe_in);
433         if (error)
434                 usage("Can't parse command-line for '%s' command",
435                     cmds[cmd].name);
436
437         if (cmd != CMD_LIST) {
438                 xbe_inp = &xbe_in;
439                 xbe_in_sz = sizeof(xbe_in);
440         } else
441                 xbe_out_szp = &xbe_out_sz;
442         if (cmd == CMD_LOOKUP) {
443                 xbe_out_sz = sizeof(xbe_out);
444                 xbe_outp = &xbe_out;
445                 xbe_out_szp = &xbe_out_sz;
446         }
447
448         error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp,
449             xbe_inp, xbe_in_sz);
450
451         if (error)
452                 switch(errno) {
453                 case EINVAL:
454                         usage("Invalid interpreter name or --interpreter, "
455                             "--magic, --mask, or --size argument value");
456                         break;
457
458                 case EEXIST:
459                         usage("'%s' is not unique in activator list",
460                             xbe_in.xbe_name);
461                         break;
462
463                 case ENOENT:
464                         usage("'%s' is not found in activator list",
465                             xbe_in.xbe_name);
466                         break;
467
468                 case ENOSPC:
469                         fatal("Fatal: no more room in the activator list "
470                             "(limited to %d enties)", IBE_MAX_ENTRIES);
471                         break;
472
473                 case EPERM:
474                         usage("Insufficient privileges for '%s' command",
475                             cmds[cmd].name);
476                         break;
477
478                 default:
479                         fatal("Fatal: sysctlbyname() returned: %s",
480                             strerror(errno));
481                         break;
482                 }
483
484
485         if (cmd == CMD_LOOKUP)
486                 printxbe(xbe_outp);
487
488         if (cmd == CMD_LIST && xbe_out_sz > 0) {
489                 xbe_outp = malloc(xbe_out_sz);
490                 if (!xbe_outp)
491                         fatal("Fatal: out of memory");
492                 while(1) {
493                         size_t osize = xbe_out_sz;
494                         error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp,
495                             &xbe_out_sz, NULL, 0);
496
497                         if (error == -1 && errno == ENOMEM &&
498                             xbe_out_sz == osize) {
499                                 /*
500                                  * Buffer too small. Increase it by one
501                                  * entry.
502                                  */
503                                 xbe_out_sz += sizeof(xbe_out);
504                                 xbe_outp = realloc(xbe_outp, xbe_out_sz);
505                                 if (!xbe_outp)
506                                         fatal("Fatal: out of memory");
507                         } else
508                                 break;
509                 }
510                 if (error) {
511                         free(xbe_outp);
512                         fatal("Fatal: %s", strerror(errno));
513                 }
514                 for(i = 0; i < howmany(xbe_out_sz, sizeof(xbe_out)); i++)
515                         printxbe(&xbe_outp[i]);
516         }
517
518         return (error);
519 }