]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/binmiscctl/binmiscctl.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <ctype.h>
32 #include <errno.h>
33 #include <getopt.h>
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include <sys/types.h>
41 #include <sys/imgact_binmisc.h>
42 #include <sys/linker.h>
43 #include <sys/sysctl.h>
44
45 enum cmd {
46         CMD_ADD = 0,
47         CMD_REMOVE,
48         CMD_DISABLE,
49         CMD_ENABLE,
50         CMD_LOOKUP,
51         CMD_LIST,
52 };
53
54 extern char *__progname;
55
56 typedef int (*cmd_func_t)(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
57
58 int add_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
59 int name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
60 int noname_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
61
62 static const struct {
63         const int token;
64         const char *name;
65         cmd_func_t func;
66         const char *desc;
67         const char *args;
68 } cmds[] = {
69         {
70                 CMD_ADD,
71                 "add",
72                 add_cmd,
73                 "Add a new binary image activator (requires 'root' privilege)",
74                 "<name> --interpreter <path_and_arguments> \\\n"
75                 "\t\t--magic <magic_bytes> [--mask <mask_bytes>] \\\n"
76                 "\t\t--size <magic_size> [--offset <magic_offset>] \\\n"
77                 "\t\t[--set-enabled]"
78         },
79         {
80                 CMD_REMOVE,
81                 "remove",
82                 name_cmd,
83                 "Remove a binary image activator (requires 'root' privilege)",
84                 "<name>"
85         },
86         {
87                 CMD_DISABLE,
88                 "disable",
89                 name_cmd,
90                 "Disable a binary image activator (requires 'root' privilege)",
91                 "<name>"
92         },
93         {
94                 CMD_ENABLE,
95                 "enable",
96                 name_cmd,
97                 "Enable a binary image activator (requires 'root' privilege)",
98                 "<name>"
99         },
100         {
101                 CMD_LOOKUP,
102                 "lookup",
103                 name_cmd,
104                 "Lookup a binary image activator",
105                 "<name>"
106         },
107         {
108                 CMD_LIST,
109                 "list",
110                 noname_cmd,
111                 "List all the binary image activators",
112                 ""
113         },
114 };
115
116 static const struct option
117 add_opts[] = {
118         { "set-enabled",        no_argument,            NULL,   'e' },
119         { "interpreter",        required_argument,      NULL,   'i' },
120         { "mask",               required_argument,      NULL,   'M' },
121         { "magic",              required_argument,      NULL,   'm' },
122         { "offset",             required_argument,      NULL,   'o' },
123         { "size",               required_argument,      NULL,   's' },
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
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 < ( sizeof (cmds) / sizeof (cmds[0])); 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
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\n", (flags & IBF_ENABLED) ? "ENABLED " : "",
195             (flags & IBF_USE_MASK) ? "USE_MASK " : "");
196         printf("magic size: %u\n", xbe->xbe_msize);
197         printf("magic offset: %u\n", xbe->xbe_moffset);
198
199         printf("magic: ");
200         for(i = 0; i < xbe->xbe_msize;  i++) {
201                 if (i && !(i % 12))
202                         printf("\n       ");
203                 else
204                         if (i && !(i % 4))
205                                 printf(" ");
206                 printf("0x%02x ", xbe->xbe_magic[i]);
207         }
208         printf("\n");
209
210         if (flags & IBF_USE_MASK) {
211                 printf("mask:  ");
212                 for(i = 0; i < xbe->xbe_msize;  i++) {
213                         if (i && !(i % 12))
214                                 printf("\n       ");
215                         else
216                                 if (i && !(i % 4))
217                                         printf(" ");
218                         printf("0x%02x ", xbe->xbe_mask[i]);
219                 }
220                 printf("\n");
221         }
222
223         printf("\n");
224 }
225
226 static int
227 demux_cmd(__unused int argc, char *const argv[])
228 {
229         size_t i;
230
231         optind = 1;
232         optreset = 1;
233
234         for(i = 0; i < ( sizeof (cmds) / sizeof (cmds[0])); i++) {
235                 if (!strcasecmp(cmds[i].name, argv[0])) {
236                         return (i);
237                 }
238         }
239
240         /* Unknown command */
241         return (-1);
242 }
243
244 static int
245 strlit2bin_cpy(uint8_t *d, char *s, size_t size)
246 {
247         int c;
248         size_t cnt = 0;
249
250         while((c = *s++) != '\0') {
251                 if (c == '\\') {
252                         /* Do '\' escapes. */
253                         switch (*s) {
254                         case '\\':
255                                 *d++ = '\\';
256                                 break;
257
258                         case 'x':
259                                 s++;
260                                 c = toupper(*s++);
261                                 *d = (c - (isdigit(c) ? '0' : ('A' - 10))) << 4;
262                                 c = toupper(*s++);
263                                 *d++ |= c - (isdigit(c) ? '0' : ('A' - 10));
264                                 break;
265
266                         default:
267                                 return (-1);
268                         }
269                 } else
270                         *d++ = c;
271
272                 if (++cnt > size)
273                         return (-1);
274         }
275
276         return (cnt);
277 }
278
279 int
280 add_cmd(__unused int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
281 {
282         int ch;
283         char *magic = NULL, *mask = NULL;
284         int sz;
285
286         if (strlen(argv[0]) > IBE_NAME_MAX)
287                 usage("'%s' string length longer than IBE_NAME_MAX (%d)",
288                     IBE_NAME_MAX);
289         strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
290
291         while ((ch = getopt_long(argc, argv, "ei:m:M:o:s:", add_opts, NULL))
292             != -1) {
293
294                 switch(ch) {
295                 case 'i':
296                         getoptstr(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX,
297                             "interpreter");
298                         break;
299
300                 case 'm':
301                         magic = strdup(optarg);
302                         break;
303
304                 case 'M':
305                         mask = strdup(optarg);
306                         xbe->xbe_flags |= IBF_USE_MASK;
307                         break;
308
309                 case 'e':
310                         xbe->xbe_flags |= IBF_ENABLED;
311                         break;
312
313                 case 'o':
314                         xbe->xbe_moffset = atol(optarg);
315                         break;
316
317                 case 's':
318                         xbe->xbe_msize = atol(optarg);
319                         if (xbe->xbe_msize == 0 ||
320                             xbe->xbe_msize > IBE_MAGIC_MAX)
321                                 usage("Error: Not valid '--size' value. "
322                                     "(Must be > 0 and < %u.)\n",
323                                     xbe->xbe_msize);
324                         break;
325
326                 default:
327                         usage("Unknown argument: '%c'", ch);
328                 }
329         }
330
331         if (xbe->xbe_msize == 0) {
332                 if (NULL != magic)
333                         free(magic);
334                 if (NULL != mask)
335                         free(mask);
336                 usage("Error: Missing '--size' argument");
337         }
338
339         if (NULL != magic) {
340                 if (xbe->xbe_msize == 0) {
341                         if (magic)
342                                 free(magic);
343                         if (mask)
344                                 free(mask);
345                         usage("Error: Missing magic size argument");
346                 }
347                 sz = strlit2bin_cpy(xbe->xbe_magic, magic, IBE_MAGIC_MAX);
348                 free(magic);
349                 if (sz == -1 || (uint32_t)sz != xbe->xbe_msize) {
350                         if (mask)
351                                 free(mask);
352                         usage("Error: invalid magic argument");
353                 }
354                 if (mask) {
355                         sz = strlit2bin_cpy(xbe->xbe_mask, mask, IBE_MAGIC_MAX);
356                         free(mask);
357                         if (sz == -1 || (uint32_t)sz != xbe->xbe_msize)
358                                 usage("Error: invalid mask argument");
359                 }
360         } else {
361                 if (mask)
362                         free(mask);
363                 usage("Error: Missing magic argument");
364         }
365
366         if (!xbe->xbe_interpreter) {
367                 usage("Error: Missing 'interpreter' argument");
368         }
369
370         return (0);
371 }
372
373 int
374 name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
375 {
376         if (argc == 0)
377                 usage("Required argument missing\n");
378         if (strlen(argv[0]) > IBE_NAME_MAX)
379                 usage("'%s' string length longer than IBE_NAME_MAX (%d)",
380                     IBE_NAME_MAX);
381         strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
382
383         return (0);
384 }
385
386 int
387 noname_cmd(__unused int argc, __unused char *argv[],
388     __unused ximgact_binmisc_entry_t *xbe)
389 {
390
391         return (0);
392 }
393
394 int
395 main(int argc, char **argv)
396 {
397         int error = 0, cmd = -1;
398         ximgact_binmisc_entry_t xbe_in, *xbe_inp = NULL;
399         ximgact_binmisc_entry_t xbe_out, *xbe_outp = NULL;
400         size_t xbe_in_sz = 0;
401         size_t xbe_out_sz = 0, *xbe_out_szp = NULL;
402         uint32_t i;
403
404         if (kldfind(KMOD_NAME) == -1) {
405                 if (kldload(KMOD_NAME) == -1)
406                         fatal("Can't load %s kernel module: %s",
407                             KMOD_NAME, strerror(errno));
408         }
409
410         bzero(&xbe_in, sizeof(xbe_in));
411         bzero(&xbe_out, sizeof(xbe_out));
412         xbe_in.xbe_version = IBE_VERSION;
413
414         if (argc < 2)
415                 usage("Error: requires at least one argument");
416
417         argc--, argv++;
418         cmd = demux_cmd(argc, argv);
419         if (cmd == -1)
420                 usage("Error: Unknown command \"%s\"", argv[0]);
421         argc--, argv++;
422
423         error = (*cmds[cmd].func)(argc, argv, &xbe_in);
424         if (error)
425                 usage("Can't parse command-line for '%s' command",
426                     cmds[cmd].name);
427
428         if (cmd != CMD_LIST) {
429                 xbe_inp = &xbe_in;
430                 xbe_in_sz = sizeof(xbe_in);
431         } else
432                 xbe_out_szp = &xbe_out_sz;
433         if (cmd == CMD_LOOKUP) {
434                 xbe_out_sz = sizeof(xbe_out);
435                 xbe_outp = &xbe_out;
436                 xbe_out_szp = &xbe_out_sz;
437         }
438
439         error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp,
440             xbe_inp, xbe_in_sz);
441
442         if (error)
443                 switch(errno) {
444                 case EINVAL:
445                         usage("Invalid interpreter name or --interpreter, "
446                             "--magic, --mask, or --size argument value");
447                         break;
448
449                 case EEXIST:
450                         usage("'%s' is not unique in activator list",
451                             xbe_in.xbe_name);
452                         break;
453
454                 case ENOENT:
455                         usage("'%s' is not found in activator list",
456                             xbe_in.xbe_name);
457                         break;
458
459                 case ENOSPC:
460                         fatal("Fatal: no more room in the activator list "
461                             "(limited to %d enties)", IBE_MAX_ENTRIES);
462                         break;
463
464                 case EPERM:
465                         usage("Insufficient privileges for '%s' command",
466                             cmds[cmd].name);
467                         break;
468
469                 default:
470                         fatal("Fatal: sysctlbyname() returned: %s",
471                             strerror(errno));
472                         break;
473                 }
474
475
476         if (cmd == CMD_LOOKUP)
477                 printxbe(xbe_outp);
478
479         if (cmd == CMD_LIST && xbe_out_sz > 0) {
480                 xbe_outp = malloc(xbe_out_sz);
481                 if (!xbe_outp)
482                         fatal("Fatal: out of memory");
483                 while(1) {
484                         size_t osize = xbe_out_sz;
485                         error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp,
486                             &xbe_out_sz, NULL, 0);
487
488                         if (error == -1 && errno == ENOMEM &&
489                             xbe_out_sz == osize) {
490                                 /*
491                                  * Buffer too small. Increase it by one
492                                  * entry.
493                                  */
494                                 xbe_out_sz += sizeof(xbe_out);
495                                 xbe_outp = realloc(xbe_outp, xbe_out_sz);
496                                 if (!xbe_outp)
497                                         fatal("Fatal: out of memory");
498                         } else
499                                 break;
500                 }
501                 if (error) {
502                         free(xbe_outp);
503                         fatal("Fatal: %s", strerror(errno));
504                 }
505                 for(i = 0; i < (xbe_out_sz / sizeof(xbe_out)); i++)
506                         printxbe(&xbe_outp[i]);
507         }
508
509         return (error);
510 }