]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/binmiscctl/binmiscctl.c
Merge bmake-20220208
[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/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/types.h>
32 #include <sys/imgact_binmisc.h>
33 #include <sys/linker.h>
34 #include <sys/module.h>
35 #include <sys/sysctl.h>
36
37 #include <ctype.h>
38 #include <errno.h>
39 #include <getopt.h>
40 #include <stdio.h>
41 #include <stdarg.h>
42 #include <stdint.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 enum cmd {
47         CMD_ADD = 0,
48         CMD_REMOVE,
49         CMD_DISABLE,
50         CMD_ENABLE,
51         CMD_LOOKUP,
52         CMD_LIST,
53 };
54
55 extern char *__progname;
56
57 typedef int (*cmd_func_t)(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
58
59 int add_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
60 int name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
61 int noname_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
62
63 static const struct {
64         const int token;
65         const char *name;
66         cmd_func_t func;
67         const char *desc;
68         const char *args;
69 } cmds[] = {
70         {
71                 CMD_ADD,
72                 "add",
73                 add_cmd,
74                 "Add a new binary image activator (requires 'root' privilege)",
75                 "<name> --interpreter <path_and_arguments> \\\n"
76                 "\t\t--magic <magic_bytes> [--mask <mask_bytes>] \\\n"
77                 "\t\t--size <magic_size> [--offset <magic_offset>] \\\n"
78                 "\t\t[--set-enabled]"
79         },
80         {
81                 CMD_REMOVE,
82                 "remove",
83                 name_cmd,
84                 "Remove a binary image activator (requires 'root' privilege)",
85                 "<name>"
86         },
87         {
88                 CMD_DISABLE,
89                 "disable",
90                 name_cmd,
91                 "Disable a binary image activator (requires 'root' privilege)",
92                 "<name>"
93         },
94         {
95                 CMD_ENABLE,
96                 "enable",
97                 name_cmd,
98                 "Enable a binary image activator (requires 'root' privilege)",
99                 "<name>"
100         },
101         {
102                 CMD_LOOKUP,
103                 "lookup",
104                 name_cmd,
105                 "Lookup a binary image activator",
106                 "<name>"
107         },
108         {
109                 CMD_LIST,
110                 "list",
111                 noname_cmd,
112                 "List all the binary image activators",
113                 ""
114         },
115 };
116
117 static const struct option
118 add_opts[] = {
119         { "set-enabled",        no_argument,            NULL,   'e' },
120         { "interpreter",        required_argument,      NULL,   'i' },
121         { "mask",               required_argument,      NULL,   'M' },
122         { "magic",              required_argument,      NULL,   'm' },
123         { "offset",             required_argument,      NULL,   'o' },
124         { "size",               required_argument,      NULL,   's' },
125         { NULL,                 0,                      NULL,   0   }
126 };
127
128 static char const *cmd_sysctl_name[] = {
129         IBE_SYSCTL_NAME_ADD,
130         IBE_SYSCTL_NAME_REMOVE,
131         IBE_SYSCTL_NAME_DISABLE,
132         IBE_SYSCTL_NAME_ENABLE,
133         IBE_SYSCTL_NAME_LOOKUP,
134         IBE_SYSCTL_NAME_LIST
135 };
136
137 static void __dead2
138 usage(const char *format, ...)
139 {
140         va_list args;
141         size_t i;
142         int error = 0;
143
144         va_start(args, format);
145         if (format) {
146                 vfprintf(stderr, format, args);
147                 error = -1;
148         }
149         va_end(args);
150         fprintf(stderr, "\n");
151         fprintf(stderr, "usage: %s command [args...]\n\n", __progname);
152
153         for(i = 0; i < nitems(cmds); i++) {
154                 fprintf(stderr, "%s:\n", cmds[i].desc);
155                 fprintf(stderr, "\t%s %s %s\n\n", __progname, cmds[i].name,
156                     cmds[i].args);
157         }
158
159         exit (error);
160 }
161
162 static void __dead2
163 fatal(const char *format, ...)
164 {
165         va_list args;
166
167         va_start(args, format);
168         if (format)
169                 vfprintf(stderr, format, args);
170         fprintf(stderr, "\n");
171
172         exit(-1);
173 }
174
175 static void
176 getoptstr(char *str, size_t size, const char *argname)
177 {
178         if (strlen(optarg) > size)
179                 usage("'%s' too large", argname);
180         strlcpy(str, optarg, size);
181 }
182
183 static void
184 printxbe(ximgact_binmisc_entry_t *xbe)
185 {
186         uint32_t i, flags = xbe->xbe_flags;
187
188         if (xbe->xbe_version != IBE_VERSION) {
189                 fprintf(stderr, "Error: XBE version mismatch\n");
190                 return;
191         }
192
193         printf("name: %s\n", xbe->xbe_name);
194         printf("interpreter: %s\n", xbe->xbe_interpreter);
195         printf("flags: %s%s\n", (flags & IBF_ENABLED) ? "ENABLED " : "",
196             (flags & IBF_USE_MASK) ? "USE_MASK " : "");
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, "ei: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                 default:
332                         usage("Unknown argument: '%c'", ch);
333                 }
334         }
335
336         if (xbe->xbe_msize == 0) {
337                 if (NULL != magic)
338                         free(magic);
339                 if (NULL != mask)
340                         free(mask);
341                 usage("Error: Missing '--size' argument");
342         }
343
344         if (NULL != magic) {
345                 if (xbe->xbe_msize == 0) {
346                         if (magic)
347                                 free(magic);
348                         if (mask)
349                                 free(mask);
350                         usage("Error: Missing magic size argument");
351                 }
352                 sz = strlit2bin_cpy(xbe->xbe_magic, magic, IBE_MAGIC_MAX);
353                 free(magic);
354                 if (sz == -1 || (uint32_t)sz != xbe->xbe_msize) {
355                         if (mask)
356                                 free(mask);
357                         usage("Error: invalid magic argument");
358                 }
359                 if (mask) {
360                         sz = strlit2bin_cpy(xbe->xbe_mask, mask, IBE_MAGIC_MAX);
361                         free(mask);
362                         if (sz == -1 || (uint32_t)sz != xbe->xbe_msize)
363                                 usage("Error: invalid mask argument");
364                 }
365         } else {
366                 if (mask)
367                         free(mask);
368                 usage("Error: Missing magic argument");
369         }
370
371         if (!strnlen(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX)) {
372                 usage("Error: Missing 'interpreter' argument");
373         }
374
375         return (0);
376 }
377
378 int
379 name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
380 {
381         if (argc == 0)
382                 usage("Required argument missing\n");
383         if (strlen(argv[0]) > IBE_NAME_MAX)
384                 usage("'%s' string length longer than IBE_NAME_MAX (%d)",
385                     IBE_NAME_MAX);
386         strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
387
388         return (0);
389 }
390
391 int
392 noname_cmd(__unused int argc, __unused char *argv[],
393     __unused ximgact_binmisc_entry_t *xbe)
394 {
395
396         return (0);
397 }
398
399 int
400 main(int argc, char **argv)
401 {
402         int error = 0, cmd = -1;
403         ximgact_binmisc_entry_t xbe_in, *xbe_inp = NULL;
404         ximgact_binmisc_entry_t xbe_out, *xbe_outp = NULL;
405         size_t xbe_in_sz = 0;
406         size_t xbe_out_sz = 0, *xbe_out_szp = NULL;
407         uint32_t i;
408
409         if (modfind(KMOD_NAME) == -1) {
410                 if (kldload(KMOD_NAME) == -1)
411                         fatal("Can't load %s kernel module: %s",
412                             KMOD_NAME, strerror(errno));
413         }
414
415         bzero(&xbe_in, sizeof(xbe_in));
416         bzero(&xbe_out, sizeof(xbe_out));
417         xbe_in.xbe_version = IBE_VERSION;
418
419         if (argc < 2)
420                 usage("Error: requires at least one argument");
421
422         argc--, argv++;
423         cmd = demux_cmd(argc, argv);
424         if (cmd < 0)
425                 usage("Error: Unknown command \"%s\"", argv[0]);
426         argc--, argv++;
427
428         error = (*cmds[cmd].func)(argc, argv, &xbe_in);
429         if (error)
430                 usage("Can't parse command-line for '%s' command",
431                     cmds[cmd].name);
432
433         if (cmd != CMD_LIST) {
434                 xbe_inp = &xbe_in;
435                 xbe_in_sz = sizeof(xbe_in);
436         } else
437                 xbe_out_szp = &xbe_out_sz;
438         if (cmd == CMD_LOOKUP) {
439                 xbe_out_sz = sizeof(xbe_out);
440                 xbe_outp = &xbe_out;
441                 xbe_out_szp = &xbe_out_sz;
442         }
443
444         error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp,
445             xbe_inp, xbe_in_sz);
446
447         if (error)
448                 switch(errno) {
449                 case EINVAL:
450                         usage("Invalid interpreter name or --interpreter, "
451                             "--magic, --mask, or --size argument value");
452                         break;
453
454                 case EEXIST:
455                         usage("'%s' is not unique in activator list",
456                             xbe_in.xbe_name);
457                         break;
458
459                 case ENOENT:
460                         usage("'%s' is not found in activator list",
461                             xbe_in.xbe_name);
462                         break;
463
464                 case ENOSPC:
465                         fatal("Fatal: no more room in the activator list "
466                             "(limited to %d enties)", IBE_MAX_ENTRIES);
467                         break;
468
469                 case EPERM:
470                         usage("Insufficient privileges for '%s' command",
471                             cmds[cmd].name);
472                         break;
473
474                 default:
475                         fatal("Fatal: sysctlbyname() returned: %s",
476                             strerror(errno));
477                         break;
478                 }
479
480
481         if (cmd == CMD_LOOKUP)
482                 printxbe(xbe_outp);
483
484         if (cmd == CMD_LIST && xbe_out_sz > 0) {
485                 xbe_outp = malloc(xbe_out_sz);
486                 if (!xbe_outp)
487                         fatal("Fatal: out of memory");
488                 while(1) {
489                         size_t osize = xbe_out_sz;
490                         error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp,
491                             &xbe_out_sz, NULL, 0);
492
493                         if (error == -1 && errno == ENOMEM &&
494                             xbe_out_sz == osize) {
495                                 /*
496                                  * Buffer too small. Increase it by one
497                                  * entry.
498                                  */
499                                 xbe_out_sz += sizeof(xbe_out);
500                                 xbe_outp = realloc(xbe_outp, xbe_out_sz);
501                                 if (!xbe_outp)
502                                         fatal("Fatal: out of memory");
503                         } else
504                                 break;
505                 }
506                 if (error) {
507                         free(xbe_outp);
508                         fatal("Fatal: %s", strerror(errno));
509                 }
510                 for(i = 0; i < howmany(xbe_out_sz, sizeof(xbe_out)); i++)
511                         printxbe(&xbe_outp[i]);
512         }
513
514         return (error);
515 }