4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (C) 2015, Trustees of Indiana University
25 * Author: Jeremy Filizetti <jfilizet@iu.edu>
37 #include <sys/types.h>
40 #include <lnet/nidstr.h>
41 #include <lustre/lustre_idl.h>
50 /* One week default expiration */
51 #define SK_DEFAULT_EXPIRE 604800
52 #define SK_DEFAULT_SK_KEYLEN 256
53 #define SK_DEFAULT_DH_KEYLEN 1024
54 #define SK_DEFAULT_NODEMAP "default"
56 /* Names match up with openssl enc and dgst commands */
57 char *sk_crypt2name[] = {
58 [SK_CRYPT_EMPTY] = "NONE",
59 [SK_CRYPT_AES256_CTR] = "AES-256-CTR",
62 char *sk_hmac2name[] = {
63 [SK_HMAC_EMPTY] = "NONE",
64 [SK_HMAC_SHA256] = "SHA256",
65 [SK_HMAC_SHA512] = "SHA512",
68 int sk_name2crypt(char *name)
72 for (i = 0; i < SK_CRYPT_MAX; i++) {
73 if (strcasecmp(name, sk_crypt2name[i]) == 0)
77 return SK_CRYPT_INVALID;
80 int sk_name2hmac(char *name)
84 for (i = 0; i < SK_HMAC_MAX; i++) {
85 if (strcasecmp(name, sk_hmac2name[i]) == 0)
89 return SK_HMAC_INVALID;
92 void usage(FILE *fp, char *program)
96 fprintf(fp, "Usage %s [OPTIONS] -l <file> | -m <file> | "
97 "-r <file> | -w <file>\n", program);
98 fprintf(fp, "-l|--load <file> Load key from file into user's "
100 fprintf(fp, "-m|--modify <file> Modify a file's key "
102 fprintf(fp, "-r|--read <file> Show file's key attributes\n");
103 fprintf(fp, "-w|--write <file> Generate key file\n\n");
104 fprintf(fp, "Load Options:\n");
105 fprintf(fp, "-t|--type <type> Key type (mgs, server, "
107 fprintf(fp, "Modify/Write Options:\n");
108 fprintf(fp, "-c|--crypt <num> Cipher for encryption "
109 "(Default: AES Counter mode)\n");
110 for (i = 0; i < SK_CRYPT_MAX; i++)
111 fprintf(fp, " %s\n", sk_crypt2name[i]);
113 fprintf(fp, "-h|--hmac <num> Hash alg for HMAC "
114 "(Default: SHA256)\n");
115 for (i = 0; i < SK_HMAC_MAX; i++)
116 fprintf(fp, " %s\n", sk_hmac2name[i]);
118 fprintf(fp, "-e|--expire <num> Seconds before contexts from "
119 "key expire (Default: %d seconds)\n", SK_DEFAULT_EXPIRE);
120 fprintf(fp, "-f|--fsname <name> File system name for key\n");
121 fprintf(fp, "-g|--mgsnids <nids> Comma seperated list of MGS "
122 "NIDs. Only required when mgssec is used (Default: "
124 fprintf(fp, "-n|--nodemap <name> Nodemap name for key "
125 "(Default: \"%s\")\n", SK_DEFAULT_NODEMAP);
126 fprintf(fp, "-s|--session <len> DHKE Public key length in bits "
127 "(Default: %d)\n", SK_DEFAULT_DH_KEYLEN);
128 fprintf(fp, "-k|--shared <len> Shared key length in bits "
129 "(Default: %d)\n", SK_DEFAULT_SK_KEYLEN);
130 fprintf(fp, "-d|--data <file> Shared key data source "
131 "(Default: /dev/random)\n\n");
132 fprintf(fp, "Other Options:\n");
133 fprintf(fp, "-v|--verbose Increase verbosity for "
138 ssize_t get_key_data(char *src, void *buffer, size_t bits)
145 /* convert bits to minimum number of bytes */
146 remain = (bits + 7) / 8;
148 fd = open(src, O_RDONLY);
150 fprintf(stderr, "Failed to open %s: %s\n", src,
156 rc = read(fd, ptr, remain);
160 fprintf(stderr, "Error reading from %s: %s\n", src,
165 } else if (rc == 0) {
166 fprintf(stderr, "Key source too short for key size\n");
180 int write_config_file(char *output_file, struct sk_keyfile_config *config,
185 int flags = O_WRONLY | O_CREAT;
190 sk_config_cpu_to_disk(config);
192 fd = open(output_file, flags, 0400);
194 fprintf(stderr, "Failed to open %s: %s\n", output_file,
199 rc = write(fd, config, sizeof(*config));
201 fprintf(stderr, "Error writing to %s: %s\n", output_file,
205 } else if (rc != sizeof(*config)) {
206 fprintf(stderr, "Short write to %s\n", output_file);
217 int print_config(char *filename)
219 struct sk_keyfile_config *config;
222 config = sk_read_file(filename);
226 if (sk_validate_config(config)) {
227 fprintf(stderr, "Key configuration failed validation\n");
232 printf("Version: %u\n", config->skc_version);
233 printf("HMAC alg: %s\n", sk_hmac2name[config->skc_hmac_alg]);
234 printf("Crypt alg: %s\n", sk_crypt2name[config->skc_crypt_alg]);
235 printf("Ctx Expiration: %u seconds\n", config->skc_expire);
236 printf("Shared keylen: %u bits\n", config->skc_shared_keylen);
237 printf("Session keylen: %u bits\n", config->skc_session_keylen);
238 printf("File system: %s\n", config->skc_fsname);
239 printf("MGS NIDs: ");
240 for (i = 0; i < MAX_MGSNIDS; i++) {
241 if (config->skc_mgsnids[i] == LNET_NID_ANY)
243 printf("%s ", libcfs_nid2str(config->skc_mgsnids[i]));
246 printf("Nodemap name: %s\n", config->skc_nodemap);
247 printf("Shared key:\n");
248 print_hex(0, config->skc_shared_key, config->skc_shared_keylen / 8);
254 int parse_mgsnids(char *mgsnids, struct sk_keyfile_config *config)
263 /* replace all old values */
264 for (i = 0; i < MAX_MGSNIDS; i++)
265 config->skc_mgsnids[i] = LNET_NID_ANY;
268 end = mgsnids + strlen(mgsnids);
270 while (ptr < end && i < MAX_MGSNIDS) {
271 sep = strstr(ptr, ",");
275 nid = libcfs_str2nid(ptr);
276 if (nid == LNET_NID_ANY) {
277 fprintf(stderr, "Invalid MGS NID: %s\n", ptr);
282 config->skc_mgsnids[i++] = nid;
283 ptr += strlen(ptr) + 1;
286 if (i == MAX_MGSNIDS) {
287 fprintf(stderr, "Too many MGS NIDs provided\n");
294 int main(int argc, char **argv)
296 struct sk_keyfile_config *config;
302 char *mgsnids = NULL;
303 char *nodemap = NULL;
305 int type = SK_TYPE_INVALID;
306 int crypt = SK_CRYPT_EMPTY;
307 int hmac = SK_HMAC_EMPTY;
309 int shared_keylen = -1;
310 int session_keylen = -1;
315 static struct option long_opt[] = {
316 {"crypt", 1, 0, 'c'},
318 {"expire", 1, 0, 'e'},
319 {"fsname", 1, 0, 'f'},
320 {"mgsnids", 1, 0, 'g'},
323 {"modify", 1, 0, 'm'},
324 {"nodemap", 1, 0, 'n'},
326 {"session", 1, 0, 's'},
327 {"shared", 1, 0, 'k'},
329 {"write", 1, 0, 'w'},
330 {"verbose", 0, 0, 'v'},
335 while ((opt = getopt_long(argc, argv, "c:d:e:f:g:h:l:m:n:pr:s:k:t:w:v",
336 long_opt, NULL)) != EOF) {
339 crypt = sk_name2crypt(optarg);
345 expire = atoi(optarg);
347 fprintf(stderr, "WARNING: Using a short key "
348 "expiration may cause issues during "
349 "key renegotiation\n");
353 if (strlen(fsname) > MTI_NAME_MAXLEN) {
354 fprintf(stderr, "File system name too long\n");
362 hmac = sk_name2hmac(optarg);
369 if (strlen(nodemap) > LUSTRE_NODEMAP_NAME_LENGTH) {
370 fprintf(stderr, "Nodemap name too long\n");
378 usage(stdout, argv[0]);
384 session_keylen = atoi(optarg);
387 shared_keylen = atoi(optarg);
390 if (!strcasecmp(optarg, "server")) {
391 type = SK_TYPE_SERVER;
392 } else if (!strcasecmp(optarg, "mgs")) {
394 } else if (!strcasecmp(optarg, "client")) {
395 type = SK_TYPE_CLIENT;
397 fprintf(stderr, "type must be mgs, server, or "
409 fprintf(stderr, "Unknown option: %c\n", opt);
415 if (optind != argc) {
416 fprintf(stderr, "Extraneous arguments provided, check usage\n");
420 if (!input && !output && !load && !modify) {
421 usage(stderr, argv[0]);
425 /* init gss logger for foreground (no syslog) which prints to stderr */
426 initerr(NULL, verbose, 1);
429 return print_config(input);
432 if (type == SK_TYPE_INVALID) {
433 fprintf(stderr, "type must be specified when loading "
438 if (sk_load_keyfile(load, type))
443 if (crypt == SK_CRYPT_INVALID) {
444 fprintf(stderr, "Invalid crypt algorithm specified\n");
447 if (hmac == SK_HMAC_INVALID) {
448 fprintf(stderr, "Invalid HMAC algorithm specified\n");
453 config = sk_read_file(modify);
457 if (crypt != SK_CRYPT_EMPTY)
458 config->skc_crypt_alg = crypt;
459 if (hmac != SK_HMAC_EMPTY)
460 config->skc_hmac_alg = hmac;
462 config->skc_expire = expire;
463 if (shared_keylen != -1)
464 config->skc_shared_keylen = shared_keylen;
465 if (session_keylen != -1)
466 config->skc_session_keylen = session_keylen;
468 strncpy(config->skc_fsname, fsname, strlen(fsname));
470 strncpy(config->skc_nodemap, nodemap, strlen(nodemap));
471 if (mgsnids && parse_mgsnids(mgsnids, config))
473 if (data && get_key_data(data, config->skc_shared_key,
474 config->skc_shared_keylen)) {
475 fprintf(stderr, "Failure getting data for key\n");
479 if (sk_validate_config(config)) {
480 fprintf(stderr, "Key configuration failed "
485 if (write_config_file(modify, config, true))
491 /* write mode for a new key */
492 if (!fsname && !mgsnids) {
493 fprintf(stderr, "Must provide --fsname, "
494 "--mgsnids, or both\n");
498 config = malloc(sizeof(*config));
502 /* Set the defaults */
503 memset(config, 0, sizeof(*config));
504 config->skc_version = SK_CONF_VERSION;
505 config->skc_expire = SK_DEFAULT_EXPIRE;
506 config->skc_shared_keylen = SK_DEFAULT_SK_KEYLEN;
507 config->skc_session_keylen = SK_DEFAULT_DH_KEYLEN;
508 config->skc_crypt_alg = SK_CRYPT_AES256_CTR;
509 config->skc_hmac_alg = SK_HMAC_SHA256;
510 for (i = 0; i < MAX_MGSNIDS; i++)
511 config->skc_mgsnids[i] = LNET_NID_ANY;
513 if (crypt != SK_CRYPT_EMPTY)
514 config->skc_crypt_alg = crypt;
515 if (hmac != SK_HMAC_EMPTY)
516 config->skc_hmac_alg = hmac;
518 config->skc_expire = expire;
519 if (shared_keylen != -1)
520 config->skc_shared_keylen = shared_keylen;
521 if (session_keylen != -1)
522 config->skc_session_keylen = session_keylen;
524 strncpy(config->skc_fsname, fsname, strlen(fsname));
526 strncpy(config->skc_nodemap, nodemap, strlen(nodemap));
528 strncpy(config->skc_nodemap, SK_DEFAULT_NODEMAP,
529 strlen(SK_DEFAULT_NODEMAP));
531 if (mgsnids && parse_mgsnids(mgsnids, config))
534 data = "/dev/random";
535 if (get_key_data(data, config->skc_shared_key,
536 config->skc_shared_keylen)) {
537 fprintf(stderr, "Failure getting data for key\n");
541 if (sk_validate_config(config)) {
542 fprintf(stderr, "Key configuration failed validation\n");
546 if (write_config_file(output, config, false))