/* * chzcrypt - Tool to modify zcrypt configuration * * Copyright IBM Corp. 2008, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include #include #include "lib/util_base.h" #include "lib/util_file.h" #include "lib/util_libc.h" #include "lib/util_opt.h" #include "lib/util_panic.h" #include "lib/util_path.h" #include "lib/util_prg.h" #include "lib/util_scandir.h" #include "lib/zt_common.h" #include "misc.h" /* * Private data */ struct chzcrypt_l { int verbose; } l; struct chzcrypt_l *chzcrypt_l = &l; /* * Program configuration */ const struct util_prg prg = { .desc = "Modify zcrypt configuration.", .args = "[DEVICE_IDS]", .copyright_vec = { { .owner = "IBM Corp.", .pub_first = 2008, .pub_last = 2017, }, UTIL_PRG_COPYRIGHT_END } }; /* * Configuration of command line options */ static struct util_opt opt_vec[] = { { .option = { "enable", no_argument, NULL, 'e'}, .argument = "DEVICE_IDS", .desc = "Set the given cryptographic device(s) online" }, { .option = { "disable", no_argument, NULL, 'd'}, .argument = "DEVICE_IDS", .desc = "Set the given cryptographic device(s) offline", }, { .option = { "all", no_argument, NULL, 'a'}, .desc = "Set all available cryptographic device(s) " "online/offline, must be used in conjunction " "with the enable or disable option", }, { .option = { "poll-thread-enable", no_argument, NULL, 'p'}, .desc = "Enable zcrypt's poll thread", }, { .option = { "poll-thread-disable", no_argument, NULL, 'n'}, .desc = "Disable zcrypt's poll thread", }, { .option = { "config-time", required_argument, NULL, 'c'}, .argument = "TIMEOUT", .desc = "Set configuration timer for re-scanning the AP bus " "to TIMEOUT seconds", }, { .option = { "poll-timeout", required_argument, NULL, 't'}, .argument = "TIMEOUT", .desc = "Set poll timer to run poll tasklet all TIMEOUT " "nanoseconds after a request has been queued", }, { .option = { "default-domain", required_argument, NULL, 'q'}, .argument = "DOMAIN", .desc = "Set new default domain to DOMAIN", }, { .option = { "verbose", no_argument, NULL, 'V'}, .desc = "Print verbose messages", }, UTIL_OPT_HELP, UTIL_OPT_VERSION, UTIL_OPT_END }; /* * Print if verbose is set */ #define verbose(x...) \ do { \ if (!l.verbose) \ break; \ printf(x); \ } while (0) /* * Set poll settings */ static void poll_thread_set(const char *mode_str) { long mode, mode_read = -1; char *attr; sscanf(mode_str, "%ld", &mode); if (mode == 1) verbose("Enabling poll thread.\n"); else verbose("Disabling poll thread.\n"); attr = util_path_sysfs("bus/ap/poll_thread"); if (!util_path_is_writable(attr)) errx(EXIT_FAILURE, "Error - can't write to %s.\n Wrong permissions" " or wrong tools version.", attr); util_file_write_l(mode, 10, attr); util_file_read_l(&mode_read, 10, attr); if (mode != mode_read) errx(EXIT_FAILURE, "Error - unable to change poll thread setting."); free(attr); } /* * Set timer */ static void config_time_set(const char *timeout_str) { long timeout, timeout_read; char *attr; if (sscanf(timeout_str, "%ld", &timeout) != 1) { errx(EXIT_FAILURE, "Error - invalid configuration timeout '%s'.", timeout_str); } attr = util_path_sysfs("bus/ap/config_time"); verbose("Setting configuration timer to %ld seconds.\n", timeout); if (!util_path_is_writable(attr)) errx(EXIT_FAILURE, "Error - can't write to %s.\n Wrong permissions" " or wrong tools version.", attr); util_file_write_l(timeout, 10, attr); util_file_read_l(&timeout_read, 10, attr); if (timeout != timeout_read) errx(EXIT_FAILURE, "Error - unable to change configuration timer setting."); free(attr); } /* * Set poll timeout */ static void poll_timeout_set(const char *poll_timeout_str) { long poll_timeout, poll_timeout_read; char *attr; if (sscanf(poll_timeout_str, "%ld", &poll_timeout) != 1) errx(EXIT_FAILURE, "Error - invalid poll timeout '%s'.", poll_timeout_str); attr = util_path_sysfs("bus/ap/poll_timeout"); verbose("Setting poll timeout to %ld seconds.\n", poll_timeout); if (!util_path_is_writable(attr)) errx(EXIT_FAILURE, "Error - can't write to %s.\n Wrong permissions" " or wrong tools version.", attr); util_file_write_l(poll_timeout, 10, attr); util_file_read_l(&poll_timeout_read, 10, attr); if (poll_timeout != poll_timeout_read) errx(EXIT_FAILURE, "Error - unable to change poll timeout setting."); free(attr); } /* * Set default domain */ static void default_domain_set(const char *default_domain_str) { long max_dom, default_domain, default_domain_read; char *attr, *ap_max_domain_id; sscanf(default_domain_str, "%li", &default_domain); ap_max_domain_id = util_path_sysfs("bus/ap/ap_max_domain_id"); util_file_read_l(&max_dom, 10, ap_max_domain_id); if (default_domain < 0 || default_domain > max_dom) errx(EXIT_FAILURE, "Error - invalid default domain '%s'.", default_domain_str); attr = util_path_sysfs("bus/ap/ap_domain"); if (!util_path_is_writable(attr)) errx(EXIT_FAILURE, "Error - can't write to %s.\n Wrong permissions" " or wrong tools version.", attr); verbose("Setting default domain to %ld.\n", default_domain); util_file_write_l(default_domain, 10, attr); util_file_read_l(&default_domain_read, 10, attr); if (default_domain != default_domain_read) errx(EXIT_FAILURE, "Error - unable to change default domain."); free(ap_max_domain_id); free(attr); } /* * Print invalid commandline error message and then exit with error code */ #define invalid_cmdline_exit(x...) \ do { \ fprintf(stderr, "%s: ", program_invocation_short_name); \ fprintf(stderr, x); \ util_prg_print_parse_error(); \ exit(EXIT_FAILURE); \ } while (0) /* * Get device list from sysfs */ static void dev_list_all(char **argz, size_t *len) { struct dirent **de_vec; int count, i; char *path; path = util_path_sysfs("bus/ap/devices/"); count = util_scandir(&de_vec, NULL, path, "card.*"); if (count < 0) errx(EXIT_FAILURE, "Error - Could not read directory %s.", path); *argz = NULL; *len = 0; for (i = 0; i < count; i++) util_assert(argz_add(argz, len, de_vec[i]->d_name) == 0, "Out of memory\n"); util_scandir_free(de_vec, count); free(path); } /* * Get device list from commandline */ static void dev_list_argv(char **argz, size_t *len, char * const argv[]) { if (argv[0] == NULL) errx(EXIT_FAILURE, "Need to specify at least one device ID."); util_assert(argz_create(argv, argz, len) == 0, "Out of memory\n"); } /* * Describe adapter ids */ void print_adapter_id_help(void) { printf("\n"); printf("DEVICE_IDS\n"); printf(" List of cryptographic device ids separated by blanks which will be set\n"); printf(" online/offline. Must be used in conjunction with the enable or disable option.\n"); printf(" DEVICE_ID could either be card device id ('') or queue device id\n"); printf(" '.').\n"); printf(" \n"); printf("EXAMPLE:\n"); printf(" Disable the cryptographic device with card id '02' (inclusive all queues).\n"); printf(" #>chzcrypt -d 02\n"); printf(" \n"); printf(" Enable the cryptographic devices with card id '03' and domain id '0005'.\n"); printf(" #>chzcrypt -e 03.0005\n"); printf(" \n"); } /* * Parse options and execute the command */ int main(int argc, char *argv[]) { const char *online, *online_text = NULL, *poll_thread, *config_time; const char *poll_timeout, *default_domain; char *path, *dev_path, *dev, *dev_list, device[256], online_read[32]; bool all = false, actionset = false; size_t len; int id, dom, c, i, j; for (i=0; i < argc; i++) for (j=2; j < (int) strlen(argv[i]); j++) if (argv[i][j] == '_') argv[i][j] = '-'; online = poll_thread = config_time = poll_timeout = default_domain = NULL; util_prg_init(&prg); util_opt_init(opt_vec, NULL); while (1) { c = util_opt_getopt_long(argc, argv); if (c == -1) break; switch (c) { case 'e': actionset = true; online = "1"; online_text = "online"; break; case 'd': actionset = true; online = "0"; online_text = "offline"; break; case 'a': all = true; break; case 'p': actionset = true; poll_thread = "1"; break; case 'n': actionset = true; poll_thread = "0"; break; case 'c': actionset = true; config_time = optarg; break; case 't': actionset = true; poll_timeout = optarg; break; case 'q': actionset = true; default_domain = optarg; break; case 'V': l.verbose = true; break; case 'h': util_prg_print_help(); util_opt_print_help(); print_adapter_id_help(); return EXIT_SUCCESS; case 'v': util_prg_print_version(); return EXIT_SUCCESS; default: util_opt_print_parse_error(c, argv); return EXIT_FAILURE; } } if (!actionset) invalid_cmdline_exit("Error - missing argument.\n"); path = util_path_sysfs("bus/ap"); if (!util_path_is_dir(path)) errx(EXIT_FAILURE, "Crypto device driver not available."); free(path); if (poll_thread) { poll_thread_set(poll_thread); return EXIT_SUCCESS; } if (config_time) { config_time_set(config_time); return EXIT_SUCCESS; } if (poll_timeout) { poll_timeout_set(poll_timeout); return EXIT_SUCCESS; } if (default_domain) { default_domain_set(default_domain); return EXIT_SUCCESS; } if (all) dev_list_all(&dev_list, &len); else dev_list_argv(&dev_list, &len, &argv[optind]); if (online && len == 0) errx(EXIT_FAILURE, "Error - missing cryptographic device id(s)."); for (dev = dev_list; dev != NULL; dev = argz_next(dev_list, len, dev)) { if (strncmp(dev, "card", 4) == 0) { /* dev == "card2" */ sscanf(dev, "card%02x", &id); sprintf(device, "card%02x", id); } else if (strncmp(dev, "0x", 2) == 0) { /* dev == "0x.." */ sscanf(dev, "0x%02x", &id); sprintf(device, "card%02x", id); } else if (misc_regex_match(dev, "^[0-9a-fA-F]+$")) { /* dev == "2" */ sscanf(dev, "%02x", &id); sprintf(device, "card%02x", id); } else { /* Form: 01.0003 ? */ if (sscanf(dev, "%02x.%04x", &id, &dom) != 2) errx(EXIT_FAILURE, "Error - cryptographic device %s malformed.", dev); sprintf(device, "card%02x/%02x.%04x", id, id, dom); } dev_path = util_path_sysfs("bus/ap/devices/%s", device); if (!util_path_is_dir(dev_path)) errx(EXIT_FAILURE, "Error - cryptographic device %s does not exist.", device); if (!util_path_is_writable("%s/online", dev_path)) errx(EXIT_FAILURE, "Error - can't write to %s/online.\n Wrong permissions" " or wrong tools version.", dev_path); verbose("Setting cryptographic device %s %s\n", device, online_text); util_file_write_s(online, "%s/online", dev_path); util_file_read_line(online_read, sizeof(online_read), "%s/online", dev_path); if (strcmp(online, online_read) != 0) errx(EXIT_FAILURE, "Error - unable to set cryptographic device %s %s.", device, online_text); free(dev_path); } free(dev_list); return EXIT_SUCCESS; }