]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/binmiscctl/binmiscctl.c
Upgrade to OpenSSH 7.5p1.
[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 <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/module.h>
44 #include <sys/sysctl.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
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 < ( sizeof (cmds) / sizeof (cmds[0])); 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
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 < ( sizeof (cmds) / sizeof (cmds[0])); 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 (strlen(argv[0]) > IBE_NAME_MAX)
288                 usage("'%s' string length longer than IBE_NAME_MAX (%d)",
289                     IBE_NAME_MAX);
290         strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
291
292         while ((ch = getopt_long(argc, argv, "ei:m:M:o:s:", add_opts, NULL))
293             != -1) {
294
295                 switch(ch) {
296                 case 'i':
297                         getoptstr(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX,
298                             "interpreter");
299                         break;
300
301                 case 'm':
302                         magic = strdup(optarg);
303                         break;
304
305                 case 'M':
306                         mask = strdup(optarg);
307                         xbe->xbe_flags |= IBF_USE_MASK;
308                         break;
309
310                 case 'e':
311                         xbe->xbe_flags |= IBF_ENABLED;
312                         break;
313
314                 case 'o':
315                         xbe->xbe_moffset = atol(optarg);
316                         break;
317
318                 case 's':
319                         xbe->xbe_msize = atol(optarg);
320                         if (xbe->xbe_msize == 0 ||
321                             xbe->xbe_msize > IBE_MAGIC_MAX)
322                                 usage("Error: Not valid '--size' value. "
323                                     "(Must be > 0 and < %u.)\n",
324                                     xbe->xbe_msize);
325                         break;
326
327                 default:
328                         usage("Unknown argument: '%c'", ch);
329                 }
330         }
331
332         if (xbe->xbe_msize == 0) {
333                 if (NULL != magic)
334                         free(magic);
335                 if (NULL != mask)
336                         free(mask);
337                 usage("Error: Missing '--size' argument");
338         }
339
340         if (NULL != magic) {
341                 if (xbe->xbe_msize == 0) {
342                         if (magic)
343                                 free(magic);
344                         if (mask)
345                                 free(mask);
346                         usage("Error: Missing magic size argument");
347                 }
348                 sz = strlit2bin_cpy(xbe->xbe_magic, magic, IBE_MAGIC_MAX);
349                 free(magic);
350                 if (sz == -1 || (uint32_t)sz != xbe->xbe_msize) {
351                         if (mask)
352                                 free(mask);
353                         usage("Error: invalid magic argument");
354                 }
355                 if (mask) {
356                         sz = strlit2bin_cpy(xbe->xbe_mask, mask, IBE_MAGIC_MAX);
357                         free(mask);
358                         if (sz == -1 || (uint32_t)sz != xbe->xbe_msize)
359                                 usage("Error: invalid mask argument");
360                 }
361         } else {
362                 if (mask)
363                         free(mask);
364                 usage("Error: Missing magic argument");
365         }
366
367         if (!strnlen(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX)) {
368                 usage("Error: Missing 'interpreter' argument");
369         }
370
371         return (0);
372 }
373
374 int
375 name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
376 {
377         if (argc == 0)
378                 usage("Required argument missing\n");
379         if (strlen(argv[0]) > IBE_NAME_MAX)
380                 usage("'%s' string length longer than IBE_NAME_MAX (%d)",
381                     IBE_NAME_MAX);
382         strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
383
384         return (0);
385 }
386
387 int
388 noname_cmd(__unused int argc, __unused char *argv[],
389     __unused ximgact_binmisc_entry_t *xbe)
390 {
391
392         return (0);
393 }
394
395 int
396 main(int argc, char **argv)
397 {
398         int error = 0, cmd = -1;
399         ximgact_binmisc_entry_t xbe_in, *xbe_inp = NULL;
400         ximgact_binmisc_entry_t xbe_out, *xbe_outp = NULL;
401         size_t xbe_in_sz = 0;
402         size_t xbe_out_sz = 0, *xbe_out_szp = NULL;
403         uint32_t i;
404
405         if (modfind(KMOD_NAME) == -1) {
406                 if (kldload(KMOD_NAME) == -1)
407                         fatal("Can't load %s kernel module: %s",
408                             KMOD_NAME, strerror(errno));
409         }
410
411         bzero(&xbe_in, sizeof(xbe_in));
412         bzero(&xbe_out, sizeof(xbe_out));
413         xbe_in.xbe_version = IBE_VERSION;
414
415         if (argc < 2)
416                 usage("Error: requires at least one argument");
417
418         argc--, argv++;
419         cmd = demux_cmd(argc, argv);
420         if (cmd < 0)
421                 usage("Error: Unknown command \"%s\"", argv[0]);
422         argc--, argv++;
423
424         error = (*cmds[cmd].func)(argc, argv, &xbe_in);
425         if (error)
426                 usage("Can't parse command-line for '%s' command",
427                     cmds[cmd].name);
428
429         if (cmd != CMD_LIST) {
430                 xbe_inp = &xbe_in;
431                 xbe_in_sz = sizeof(xbe_in);
432         } else
433                 xbe_out_szp = &xbe_out_sz;
434         if (cmd == CMD_LOOKUP) {
435                 xbe_out_sz = sizeof(xbe_out);
436                 xbe_outp = &xbe_out;
437                 xbe_out_szp = &xbe_out_sz;
438         }
439
440         error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp,
441             xbe_inp, xbe_in_sz);
442
443         if (error)
444                 switch(errno) {
445                 case EINVAL:
446                         usage("Invalid interpreter name or --interpreter, "
447                             "--magic, --mask, or --size argument value");
448                         break;
449
450                 case EEXIST:
451                         usage("'%s' is not unique in activator list",
452                             xbe_in.xbe_name);
453                         break;
454
455                 case ENOENT:
456                         usage("'%s' is not found in activator list",
457                             xbe_in.xbe_name);
458                         break;
459
460                 case ENOSPC:
461                         fatal("Fatal: no more room in the activator list "
462                             "(limited to %d enties)", IBE_MAX_ENTRIES);
463                         break;
464
465                 case EPERM:
466                         usage("Insufficient privileges for '%s' command",
467                             cmds[cmd].name);
468                         break;
469
470                 default:
471                         fatal("Fatal: sysctlbyname() returned: %s",
472                             strerror(errno));
473                         break;
474                 }
475
476
477         if (cmd == CMD_LOOKUP)
478                 printxbe(xbe_outp);
479
480         if (cmd == CMD_LIST && xbe_out_sz > 0) {
481                 xbe_outp = malloc(xbe_out_sz);
482                 if (!xbe_outp)
483                         fatal("Fatal: out of memory");
484                 while(1) {
485                         size_t osize = xbe_out_sz;
486                         error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp,
487                             &xbe_out_sz, NULL, 0);
488
489                         if (error == -1 && errno == ENOMEM &&
490                             xbe_out_sz == osize) {
491                                 /*
492                                  * Buffer too small. Increase it by one
493                                  * entry.
494                                  */
495                                 xbe_out_sz += sizeof(xbe_out);
496                                 xbe_outp = realloc(xbe_outp, xbe_out_sz);
497                                 if (!xbe_outp)
498                                         fatal("Fatal: out of memory");
499                         } else
500                                 break;
501                 }
502                 if (error) {
503                         free(xbe_outp);
504                         fatal("Fatal: %s", strerror(errno));
505                 }
506                 for(i = 0; i < (xbe_out_sz / sizeof(xbe_out)); i++)
507                         printxbe(&xbe_outp[i]);
508         }
509
510         return (error);
511 }