summaryrefslogtreecommitdiffstats
path: root/usr.sbin/binmiscctl/binmiscctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/binmiscctl/binmiscctl.c')
-rw-r--r--usr.sbin/binmiscctl/binmiscctl.c510
1 files changed, 510 insertions, 0 deletions
diff --git a/usr.sbin/binmiscctl/binmiscctl.c b/usr.sbin/binmiscctl/binmiscctl.c
new file mode 100644
index 0000000..5ab82e4
--- /dev/null
+++ b/usr.sbin/binmiscctl/binmiscctl.c
@@ -0,0 +1,510 @@
+/*-
+ * Copyright (c) 2013 Stacey D. Son
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/imgact_binmisc.h>
+#include <sys/linker.h>
+#include <sys/sysctl.h>
+
+enum cmd {
+ CMD_ADD = 0,
+ CMD_REMOVE,
+ CMD_DISABLE,
+ CMD_ENABLE,
+ CMD_LOOKUP,
+ CMD_LIST,
+};
+
+extern char *__progname;
+
+typedef int (*cmd_func_t)(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
+
+int add_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
+int name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
+int noname_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
+
+static const struct {
+ const int token;
+ const char *name;
+ cmd_func_t func;
+ const char *desc;
+ const char *args;
+} cmds[] = {
+ {
+ CMD_ADD,
+ "add",
+ add_cmd,
+ "Add a new binary image activator (requires 'root' privilege)",
+ "<name> --interpreter <path_and_arguments> \\\n"
+ "\t\t--magic <magic_bytes> [--mask <mask_bytes>] \\\n"
+ "\t\t--size <magic_size> [--offset <magic_offset>] \\\n"
+ "\t\t[--set-enabled]"
+ },
+ {
+ CMD_REMOVE,
+ "remove",
+ name_cmd,
+ "Remove a binary image activator (requires 'root' privilege)",
+ "<name>"
+ },
+ {
+ CMD_DISABLE,
+ "disable",
+ name_cmd,
+ "Disable a binary image activator (requires 'root' privilege)",
+ "<name>"
+ },
+ {
+ CMD_ENABLE,
+ "enable",
+ name_cmd,
+ "Enable a binary image activator (requires 'root' privilege)",
+ "<name>"
+ },
+ {
+ CMD_LOOKUP,
+ "lookup",
+ name_cmd,
+ "Lookup a binary image activator",
+ "<name>"
+ },
+ {
+ CMD_LIST,
+ "list",
+ noname_cmd,
+ "List all the binary image activators",
+ ""
+ },
+};
+
+static const struct option
+add_opts[] = {
+ { "set-enabled", no_argument, NULL, 'e' },
+ { "interpreter", required_argument, NULL, 'i' },
+ { "mask", required_argument, NULL, 'M' },
+ { "magic", required_argument, NULL, 'm' },
+ { "offset", required_argument, NULL, 'o' },
+ { "size", required_argument, NULL, 's' },
+ { NULL, 0, NULL, 0 }
+};
+
+static char const *cmd_sysctl_name[] = {
+ IBE_SYSCTL_NAME_ADD,
+ IBE_SYSCTL_NAME_REMOVE,
+ IBE_SYSCTL_NAME_DISABLE,
+ IBE_SYSCTL_NAME_ENABLE,
+ IBE_SYSCTL_NAME_LOOKUP,
+ IBE_SYSCTL_NAME_LIST
+};
+
+static void
+usage(const char *format, ...)
+{
+ va_list args;
+ size_t i;
+ int error = 0;
+
+ va_start(args, format);
+ if (format) {
+ vfprintf(stderr, format, args);
+ error = -1;
+ }
+ va_end(args);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "usage: %s command [args...]\n\n", __progname);
+
+ for(i = 0; i < ( sizeof (cmds) / sizeof (cmds[0])); i++) {
+ fprintf(stderr, "%s:\n", cmds[i].desc);
+ fprintf(stderr, "\t%s %s %s\n\n", __progname, cmds[i].name,
+ cmds[i].args);
+ }
+
+ exit (error);
+}
+
+static void
+fatal(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ if (format)
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+
+ exit(-1);
+}
+
+static void
+getoptstr(char *str, size_t size, const char *argname)
+{
+ if (strlen(optarg) > size)
+ usage("'%s' too large", argname);
+ strlcpy(str, optarg, size);
+}
+
+static void
+printxbe(ximgact_binmisc_entry_t *xbe)
+{
+ uint32_t i, flags = xbe->xbe_flags;
+
+ if (xbe->xbe_version != IBE_VERSION) {
+ fprintf(stderr, "Error: XBE version mismatch\n");
+ return;
+ }
+
+ printf("name: %s\n", xbe->xbe_name);
+ printf("interpreter: %s\n", xbe->xbe_interpreter);
+ printf("flags: %s%s\n", (flags & IBF_ENABLED) ? "ENABLED " : "",
+ (flags & IBF_USE_MASK) ? "USE_MASK " : "");
+ printf("magic size: %u\n", xbe->xbe_msize);
+ printf("magic offset: %u\n", xbe->xbe_moffset);
+
+ printf("magic: ");
+ for(i = 0; i < xbe->xbe_msize; i++) {
+ if (i && !(i % 12))
+ printf("\n ");
+ else
+ if (i && !(i % 4))
+ printf(" ");
+ printf("0x%02x ", xbe->xbe_magic[i]);
+ }
+ printf("\n");
+
+ if (flags & IBF_USE_MASK) {
+ printf("mask: ");
+ for(i = 0; i < xbe->xbe_msize; i++) {
+ if (i && !(i % 12))
+ printf("\n ");
+ else
+ if (i && !(i % 4))
+ printf(" ");
+ printf("0x%02x ", xbe->xbe_mask[i]);
+ }
+ printf("\n");
+ }
+
+ printf("\n");
+}
+
+static int
+demux_cmd(__unused int argc, char *const argv[])
+{
+ size_t i;
+
+ optind = 1;
+ optreset = 1;
+
+ for(i = 0; i < ( sizeof (cmds) / sizeof (cmds[0])); i++) {
+ if (!strcasecmp(cmds[i].name, argv[0])) {
+ return (i);
+ }
+ }
+
+ /* Unknown command */
+ return (-1);
+}
+
+static int
+strlit2bin_cpy(uint8_t *d, char *s, size_t size)
+{
+ int c;
+ size_t cnt = 0;
+
+ while((c = *s++) != '\0') {
+ if (c == '\\') {
+ /* Do '\' escapes. */
+ switch (*s) {
+ case '\\':
+ *d++ = '\\';
+ break;
+
+ case 'x':
+ s++;
+ c = toupper(*s++);
+ *d = (c - (isdigit(c) ? '0' : ('A' - 10))) << 4;
+ c = toupper(*s++);
+ *d++ |= c - (isdigit(c) ? '0' : ('A' - 10));
+ break;
+
+ default:
+ return (-1);
+ }
+ } else
+ *d++ = c;
+
+ if (++cnt > size)
+ return (-1);
+ }
+
+ return (cnt);
+}
+
+int
+add_cmd(__unused int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
+{
+ int ch;
+ char *magic = NULL, *mask = NULL;
+ int sz;
+
+ if (strlen(argv[0]) > IBE_NAME_MAX)
+ usage("'%s' string length longer than IBE_NAME_MAX (%d)",
+ IBE_NAME_MAX);
+ strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
+
+ while ((ch = getopt_long(argc, argv, "ei:m:M:o:s:", add_opts, NULL))
+ != -1) {
+
+ switch(ch) {
+ case 'i':
+ getoptstr(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX,
+ "interpreter");
+ break;
+
+ case 'm':
+ magic = strdup(optarg);
+ break;
+
+ case 'M':
+ mask = strdup(optarg);
+ xbe->xbe_flags |= IBF_USE_MASK;
+ break;
+
+ case 'e':
+ xbe->xbe_flags |= IBF_ENABLED;
+ break;
+
+ case 'o':
+ xbe->xbe_moffset = atol(optarg);
+ break;
+
+ case 's':
+ xbe->xbe_msize = atol(optarg);
+ if (xbe->xbe_msize == 0 ||
+ xbe->xbe_msize > IBE_MAGIC_MAX)
+ usage("Error: Not valid '--size' value. "
+ "(Must be > 0 and < %u.)\n",
+ xbe->xbe_msize);
+ break;
+
+ default:
+ usage("Unknown argument: '%c'", ch);
+ }
+ }
+
+ if (xbe->xbe_msize == 0) {
+ if (NULL != magic)
+ free(magic);
+ if (NULL != mask)
+ free(mask);
+ usage("Error: Missing '--size' argument");
+ }
+
+ if (NULL != magic) {
+ if (xbe->xbe_msize == 0) {
+ if (magic)
+ free(magic);
+ if (mask)
+ free(mask);
+ usage("Error: Missing magic size argument");
+ }
+ sz = strlit2bin_cpy(xbe->xbe_magic, magic, IBE_MAGIC_MAX);
+ free(magic);
+ if (sz == -1 || (uint32_t)sz != xbe->xbe_msize) {
+ if (mask)
+ free(mask);
+ usage("Error: invalid magic argument");
+ }
+ if (mask) {
+ sz = strlit2bin_cpy(xbe->xbe_mask, mask, IBE_MAGIC_MAX);
+ free(mask);
+ if (sz == -1 || (uint32_t)sz != xbe->xbe_msize)
+ usage("Error: invalid mask argument");
+ }
+ } else {
+ if (mask)
+ free(mask);
+ usage("Error: Missing magic argument");
+ }
+
+ if (!strnlen(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX)) {
+ usage("Error: Missing 'interpreter' argument");
+ }
+
+ return (0);
+}
+
+int
+name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
+{
+ if (argc == 0)
+ usage("Required argument missing\n");
+ if (strlen(argv[0]) > IBE_NAME_MAX)
+ usage("'%s' string length longer than IBE_NAME_MAX (%d)",
+ IBE_NAME_MAX);
+ strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
+
+ return (0);
+}
+
+int
+noname_cmd(__unused int argc, __unused char *argv[],
+ __unused ximgact_binmisc_entry_t *xbe)
+{
+
+ return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+ int error = 0, cmd = -1;
+ ximgact_binmisc_entry_t xbe_in, *xbe_inp = NULL;
+ ximgact_binmisc_entry_t xbe_out, *xbe_outp = NULL;
+ size_t xbe_in_sz = 0;
+ size_t xbe_out_sz = 0, *xbe_out_szp = NULL;
+ uint32_t i;
+
+ if (kldfind(KMOD_NAME) == -1) {
+ if (kldload(KMOD_NAME) == -1)
+ fatal("Can't load %s kernel module: %s",
+ KMOD_NAME, strerror(errno));
+ }
+
+ bzero(&xbe_in, sizeof(xbe_in));
+ bzero(&xbe_out, sizeof(xbe_out));
+ xbe_in.xbe_version = IBE_VERSION;
+
+ if (argc < 2)
+ usage("Error: requires at least one argument");
+
+ argc--, argv++;
+ cmd = demux_cmd(argc, argv);
+ if (cmd == -1)
+ usage("Error: Unknown command \"%s\"", argv[0]);
+ argc--, argv++;
+
+ error = (*cmds[cmd].func)(argc, argv, &xbe_in);
+ if (error)
+ usage("Can't parse command-line for '%s' command",
+ cmds[cmd].name);
+
+ if (cmd != CMD_LIST) {
+ xbe_inp = &xbe_in;
+ xbe_in_sz = sizeof(xbe_in);
+ } else
+ xbe_out_szp = &xbe_out_sz;
+ if (cmd == CMD_LOOKUP) {
+ xbe_out_sz = sizeof(xbe_out);
+ xbe_outp = &xbe_out;
+ xbe_out_szp = &xbe_out_sz;
+ }
+
+ error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp,
+ xbe_inp, xbe_in_sz);
+
+ if (error)
+ switch(errno) {
+ case EINVAL:
+ usage("Invalid interpreter name or --interpreter, "
+ "--magic, --mask, or --size argument value");
+ break;
+
+ case EEXIST:
+ usage("'%s' is not unique in activator list",
+ xbe_in.xbe_name);
+ break;
+
+ case ENOENT:
+ usage("'%s' is not found in activator list",
+ xbe_in.xbe_name);
+ break;
+
+ case ENOSPC:
+ fatal("Fatal: no more room in the activator list "
+ "(limited to %d enties)", IBE_MAX_ENTRIES);
+ break;
+
+ case EPERM:
+ usage("Insufficient privileges for '%s' command",
+ cmds[cmd].name);
+ break;
+
+ default:
+ fatal("Fatal: sysctlbyname() returned: %s",
+ strerror(errno));
+ break;
+ }
+
+
+ if (cmd == CMD_LOOKUP)
+ printxbe(xbe_outp);
+
+ if (cmd == CMD_LIST && xbe_out_sz > 0) {
+ xbe_outp = malloc(xbe_out_sz);
+ if (!xbe_outp)
+ fatal("Fatal: out of memory");
+ while(1) {
+ size_t osize = xbe_out_sz;
+ error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp,
+ &xbe_out_sz, NULL, 0);
+
+ if (error == -1 && errno == ENOMEM &&
+ xbe_out_sz == osize) {
+ /*
+ * Buffer too small. Increase it by one
+ * entry.
+ */
+ xbe_out_sz += sizeof(xbe_out);
+ xbe_outp = realloc(xbe_outp, xbe_out_sz);
+ if (!xbe_outp)
+ fatal("Fatal: out of memory");
+ } else
+ break;
+ }
+ if (error) {
+ free(xbe_outp);
+ fatal("Fatal: %s", strerror(errno));
+ }
+ for(i = 0; i < (xbe_out_sz / sizeof(xbe_out)); i++)
+ printxbe(&xbe_outp[i]);
+ }
+
+ return (error);
+}
OpenPOWER on IntegriCloud