summaryrefslogtreecommitdiffstats
path: root/src/tools/ceph_authtool.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/ceph_authtool.cc')
-rw-r--r--src/tools/ceph_authtool.cc314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/tools/ceph_authtool.cc b/src/tools/ceph_authtool.cc
new file mode 100644
index 000000000..c650cc880
--- /dev/null
+++ b/src/tools/ceph_authtool.cc
@@ -0,0 +1,314 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include "common/ConfUtils.h"
+#include "common/ceph_argparse.h"
+#include "common/config_proxy.h"
+#include "global/global_context.h"
+#include "global/global_init.h"
+
+#include "auth/Crypto.h"
+#include "auth/Auth.h"
+#include "auth/KeyRing.h"
+
+void usage()
+{
+ cout << "usage: ceph-authtool keyringfile [OPTIONS]...\n"
+ << "where the options are:\n"
+ << " -l, --list will list all keys and capabilities present in\n"
+ << " the keyring\n"
+ << " -p, --print-key will print an encoded key for the specified\n"
+ << " entityname. This is suitable for the\n"
+ << " 'mount -o secret=..' argument\n"
+ << " -C, --create-keyring will create a new keyring, overwriting any\n"
+ << " existing keyringfile\n"
+ << " -g, --gen-key will generate a new secret key for the\n"
+ << " specified entityname\n"
+ << " --gen-print-key will generate a new secret key without set it\n"
+ << " to the keyringfile, prints the secret to stdout\n"
+ << " --import-keyring FILE will import the content of a given keyring\n"
+ << " into the keyringfile\n"
+ << " -n NAME, --name NAME specify entityname to operate on\n"
+ << " -a BASE64, --add-key BASE64 will add an encoded key to the keyring\n"
+ << " --cap SUBSYSTEM CAPABILITY will set the capability for given subsystem\n"
+ << " --caps CAPSFILE will set all of capabilities associated with a\n"
+ << " given key, for all subsystems\n"
+ << " --mode MODE will set the desired file mode to the keyring\n"
+ << " e.g: '0644', defaults to '0600'"
+ << std::endl;
+ exit(1);
+}
+
+int main(int argc, const char **argv)
+{
+ vector<const char*> args;
+ argv_to_vec(argc, argv, args);
+
+ std::string add_key;
+ std::string caps_fn;
+ std::string import_keyring;
+ map<string,bufferlist> caps;
+ std::string fn;
+
+ if (args.empty()) {
+ cerr << argv[0] << ": -h or --help for usage" << std::endl;
+ exit(1);
+ }
+ if (ceph_argparse_need_usage(args)) {
+ usage();
+ exit(0);
+ }
+
+ auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
+ CODE_ENVIRONMENT_UTILITY,
+ CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
+
+ bool gen_key = false;
+ bool gen_print_key = false;
+ bool list = false;
+ bool print_key = false;
+ bool create_keyring = false;
+ int mode = 0600; // keyring file mode
+ std::vector<const char*>::iterator i;
+
+ /* Handle options unique to ceph-authtool
+ * -n NAME, --name NAME is handled by global_init
+ * */
+ for (i = args.begin(); i != args.end(); ) {
+ std::string val;
+ if (ceph_argparse_double_dash(args, i)) {
+ break;
+ } else if (ceph_argparse_flag(args, i, "-g", "--gen-key", (char*)NULL)) {
+ gen_key = true;
+ } else if (ceph_argparse_flag(args, i, "--gen-print-key", (char*)NULL)) {
+ gen_print_key = true;
+ } else if (ceph_argparse_witharg(args, i, &val, "-a", "--add-key", (char*)NULL)) {
+ if (val.empty()) {
+ cerr << "Option --add-key requires an argument" << std::endl;
+ exit(1);
+ }
+ add_key = val;
+ } else if (ceph_argparse_flag(args, i, "-l", "--list", (char*)NULL)) {
+ list = true;
+ } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) {
+ caps_fn = val;
+ } else if (ceph_argparse_witharg(args, i, &val, "--cap", (char*)NULL)) {
+ std::string my_key = val;
+ if (i == args.end()) {
+ cerr << "must give two arguments to --cap: key and val." << std::endl;
+ exit(1);
+ }
+ std::string my_val = *i;
+ ++i;
+ encode(my_val, caps[my_key]);
+ } else if (ceph_argparse_flag(args, i, "-p", "--print-key", (char*)NULL)) {
+ print_key = true;
+ } else if (ceph_argparse_flag(args, i, "-C", "--create-keyring", (char*)NULL)) {
+ create_keyring = true;
+ } else if (ceph_argparse_witharg(args, i, &val, "--import-keyring", (char*)NULL)) {
+ import_keyring = val;
+ } else if (ceph_argparse_witharg(args, i, &val, "--mode", (char*)NULL)) {
+ std::string err;
+ mode = strict_strtoll(val.c_str(), 8, &err);
+ if (!err.empty()) {
+ cerr << "Option --mode requires an argument" << std::endl;
+ exit(1);
+ }
+ } else if (fn.empty()) {
+ fn = *i++;
+ } else {
+ cerr << argv[0] << ": unexpected '" << *i << "'" << std::endl;
+ usage();
+ }
+ }
+
+ if (fn.empty() && !gen_print_key) {
+ cerr << argv[0] << ": must specify filename" << std::endl;
+ usage();
+ }
+ if (!(gen_key ||
+ gen_print_key ||
+ !add_key.empty() ||
+ list ||
+ !caps_fn.empty() ||
+ !caps.empty() ||
+ print_key ||
+ create_keyring ||
+ !import_keyring.empty())) {
+ cerr << "no command specified" << std::endl;
+ usage();
+ }
+ if (gen_key && (!add_key.empty())) {
+ cerr << "can't both gen-key and add-key" << std::endl;
+ usage();
+ }
+
+ common_init_finish(g_ceph_context);
+ EntityName ename(g_conf()->name);
+
+ // Enforce the use of gen-key or add-key when creating to avoid ending up
+ // with an "empty" key (key = AAAAAAAAAAAAAAAA)
+ if (create_keyring && !gen_key && add_key.empty() && !caps.empty()) {
+ cerr << "must specify either gen-key or add-key when creating" << std::endl;
+ usage();
+ }
+
+ if (gen_print_key) {
+ CryptoKey key;
+ key.create(g_ceph_context, CEPH_CRYPTO_AES);
+ cout << key << std::endl;
+ return 0;
+ }
+
+ // keyring --------
+ bool modified = false;
+ bool added_entity = false;
+ KeyRing keyring;
+
+ bufferlist bl;
+ int r = 0;
+ if (create_keyring) {
+ cout << "creating " << fn << std::endl;
+ modified = true;
+ } else {
+ std::string err;
+ r = bl.read_file(fn.c_str(), &err);
+ if (r >= 0) {
+ try {
+ auto iter = bl.cbegin();
+ decode(keyring, iter);
+ } catch (const buffer::error &err) {
+ cerr << "error reading file " << fn << std::endl;
+ exit(1);
+ }
+ } else {
+ cerr << "can't open " << fn << ": " << err << std::endl;
+ exit(1);
+ }
+ }
+
+ // Validate that "name" actually has an existing key in this keyring if we
+ // have not given gen-key or add-key options
+ if (!gen_key && add_key.empty() && !caps.empty()) {
+ CryptoKey key;
+ if (!keyring.get_secret(ename, key)) {
+ cerr << "can't find existing key for " << ename
+ << " and neither gen-key nor add-key specified" << std::endl;
+ exit(1);
+ }
+ }
+
+ // write commands
+ if (!import_keyring.empty()) {
+ KeyRing other;
+ bufferlist obl;
+ std::string err;
+ int r = obl.read_file(import_keyring.c_str(), &err);
+ if (r >= 0) {
+ try {
+ auto iter = obl.cbegin();
+ decode(other, iter);
+ } catch (const buffer::error &err) {
+ cerr << "error reading file " << import_keyring << std::endl;
+ exit(1);
+ }
+
+ cout << "importing contents of " << import_keyring << " into " << fn << std::endl;
+ //other.print(cout);
+ keyring.import(g_ceph_context, other);
+ modified = true;
+ } else {
+ cerr << "can't open " << import_keyring << ": " << err << std::endl;
+ exit(1);
+ }
+ }
+ if (gen_key) {
+ EntityAuth eauth;
+ eauth.key.create(g_ceph_context, CEPH_CRYPTO_AES);
+ keyring.add(ename, eauth);
+ modified = true;
+ }
+ if (!add_key.empty()) {
+ EntityAuth eauth;
+ try {
+ eauth.key.decode_base64(add_key);
+ } catch (const buffer::error &err) {
+ cerr << "can't decode key '" << add_key << "'" << std::endl;
+ exit(1);
+ }
+ keyring.add(ename, eauth);
+ modified = true;
+ cout << "added entity " << ename << " " << eauth << std::endl;
+ added_entity = true;
+ }
+ if (!caps_fn.empty()) {
+ ConfFile cf;
+ if (cf.parse_file(caps_fn, &cerr) != 0) {
+ cerr << "could not parse caps file " << caps_fn << std::endl;
+ exit(1);
+ }
+ map<string, bufferlist> caps;
+ const char *key_names[] = { "mon", "osd", "mds", "mgr", NULL };
+ for (int i=0; key_names[i]; i++) {
+ std::string val;
+ if (cf.read("global", key_names[i], val) == 0) {
+ bufferlist bl;
+ encode(val, bl);
+ string s(key_names[i]);
+ caps[s] = bl;
+ }
+ }
+ keyring.set_caps(ename, caps);
+ modified = true;
+ }
+ if (!caps.empty()) {
+ keyring.set_caps(ename, caps);
+ modified = true;
+ }
+ if (added_entity && caps.size() > 0) {
+ cout << "added " << caps.size() << " caps to entity " << ename << std::endl;
+ }
+
+ // read commands
+ if (list) {
+ try {
+ keyring.print(cout);
+ } catch (ceph::buffer::end_of_buffer &eob) {
+ cout << "Exception (end_of_buffer) in print(), exit." << std::endl;
+ exit(1);
+ }
+ }
+ if (print_key) {
+ CryptoKey key;
+ if (keyring.get_secret(ename, key)) {
+ cout << key << std::endl;
+ } else {
+ cerr << "entity " << ename << " not found" << std::endl;
+ exit(1);
+ }
+ }
+
+ // write result?
+ if (modified) {
+ bufferlist bl;
+ keyring.encode_plaintext(bl);
+ r = bl.write_file(fn.c_str(), mode);
+ if (r < 0) {
+ cerr << "could not write " << fn << std::endl;
+ exit(1);
+ }
+ //cout << "wrote " << bl.length() << " bytes to " << fn << std::endl;
+ }
+ return 0;
+}