]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/ceph_authtool.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / tools / ceph_authtool.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#include "common/ConfUtils.h"
16#include "common/ceph_argparse.h"
11fdf7f2 17#include "common/config_proxy.h"
7c673cae
FG
18#include "global/global_context.h"
19#include "global/global_init.h"
20
21#include "auth/Crypto.h"
22#include "auth/Auth.h"
23#include "auth/KeyRing.h"
24
25void usage()
26{
27 cout << "usage: ceph-authtool keyringfile [OPTIONS]...\n"
28 << "where the options are:\n"
29 << " -l, --list will list all keys and capabilities present in\n"
30 << " the keyring\n"
31 << " -p, --print-key will print an encoded key for the specified\n"
32 << " entityname. This is suitable for the\n"
33 << " 'mount -o secret=..' argument\n"
34 << " -C, --create-keyring will create a new keyring, overwriting any\n"
35 << " existing keyringfile\n"
36 << " -g, --gen-key will generate a new secret key for the\n"
37 << " specified entityname\n"
38 << " --gen-print-key will generate a new secret key without set it\n"
39 << " to the keyringfile, prints the secret to stdout\n"
40 << " --import-keyring FILE will import the content of a given keyring\n"
41 << " into the keyringfile\n"
42 << " -n NAME, --name NAME specify entityname to operate on\n"
7c673cae
FG
43 << " -a BASE64, --add-key BASE64 will add an encoded key to the keyring\n"
44 << " --cap SUBSYSTEM CAPABILITY will set the capability for given subsystem\n"
45 << " --caps CAPSFILE will set all of capabilities associated with a\n"
94b18763
FG
46 << " given key, for all subsystems\n"
47 << " --mode MODE will set the desired file mode to the keyring\n"
48 << " e.g: '0644', defaults to '0600'"
7c673cae
FG
49 << std::endl;
50 exit(1);
51}
52
53int main(int argc, const char **argv)
54{
55 vector<const char*> args;
56 argv_to_vec(argc, argv, args);
7c673cae
FG
57
58 std::string add_key;
59 std::string caps_fn;
60 std::string import_keyring;
7c673cae
FG
61 map<string,bufferlist> caps;
62 std::string fn;
63
11fdf7f2
TL
64 if (args.empty()) {
65 cerr << argv[0] << ": -h or --help for usage" << std::endl;
66 exit(1);
67 }
68 if (ceph_argparse_need_usage(args)) {
69 usage();
70 exit(0);
71 }
72
7c673cae
FG
73 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
74 CODE_ENVIRONMENT_UTILITY,
75 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
76
77 bool gen_key = false;
78 bool gen_print_key = false;
79 bool list = false;
80 bool print_key = false;
81 bool create_keyring = false;
94b18763 82 int mode = 0600; // keyring file mode
7c673cae
FG
83 std::vector<const char*>::iterator i;
84
85 /* Handle options unique to ceph-authtool
86 * -n NAME, --name NAME is handled by global_init
87 * */
88 for (i = args.begin(); i != args.end(); ) {
89 std::string val;
90 if (ceph_argparse_double_dash(args, i)) {
91 break;
92 } else if (ceph_argparse_flag(args, i, "-g", "--gen-key", (char*)NULL)) {
93 gen_key = true;
94 } else if (ceph_argparse_flag(args, i, "--gen-print-key", (char*)NULL)) {
95 gen_print_key = true;
96 } else if (ceph_argparse_witharg(args, i, &val, "-a", "--add-key", (char*)NULL)) {
97 if (val.empty()) {
98 cerr << "Option --add-key requires an argument" << std::endl;
99 exit(1);
100 }
101 add_key = val;
102 } else if (ceph_argparse_flag(args, i, "-l", "--list", (char*)NULL)) {
103 list = true;
104 } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) {
105 caps_fn = val;
106 } else if (ceph_argparse_witharg(args, i, &val, "--cap", (char*)NULL)) {
107 std::string my_key = val;
108 if (i == args.end()) {
109 cerr << "must give two arguments to --cap: key and val." << std::endl;
110 exit(1);
111 }
112 std::string my_val = *i;
113 ++i;
11fdf7f2 114 encode(my_val, caps[my_key]);
7c673cae
FG
115 } else if (ceph_argparse_flag(args, i, "-p", "--print-key", (char*)NULL)) {
116 print_key = true;
117 } else if (ceph_argparse_flag(args, i, "-C", "--create-keyring", (char*)NULL)) {
118 create_keyring = true;
119 } else if (ceph_argparse_witharg(args, i, &val, "--import-keyring", (char*)NULL)) {
120 import_keyring = val;
94b18763
FG
121 } else if (ceph_argparse_witharg(args, i, &val, "--mode", (char*)NULL)) {
122 std::string err;
123 mode = strict_strtoll(val.c_str(), 8, &err);
124 if (!err.empty()) {
125 cerr << "Option --mode requires an argument" << std::endl;
126 exit(1);
127 }
7c673cae
FG
128 } else if (fn.empty()) {
129 fn = *i++;
130 } else {
131 cerr << argv[0] << ": unexpected '" << *i << "'" << std::endl;
132 usage();
133 }
134 }
135
136 if (fn.empty() && !gen_print_key) {
137 cerr << argv[0] << ": must specify filename" << std::endl;
138 usage();
139 }
140 if (!(gen_key ||
141 gen_print_key ||
142 !add_key.empty() ||
143 list ||
144 !caps_fn.empty() ||
145 !caps.empty() ||
7c673cae
FG
146 print_key ||
147 create_keyring ||
148 !import_keyring.empty())) {
149 cerr << "no command specified" << std::endl;
150 usage();
151 }
152 if (gen_key && (!add_key.empty())) {
153 cerr << "can't both gen-key and add-key" << std::endl;
154 usage();
155 }
156
157 common_init_finish(g_ceph_context);
11fdf7f2 158 EntityName ename(g_conf()->name);
7c673cae
FG
159
160 // Enforce the use of gen-key or add-key when creating to avoid ending up
161 // with an "empty" key (key = AAAAAAAAAAAAAAAA)
162 if (create_keyring && !gen_key && add_key.empty() && !caps.empty()) {
163 cerr << "must specify either gen-key or add-key when creating" << std::endl;
164 usage();
165 }
166
167 if (gen_print_key) {
168 CryptoKey key;
169 key.create(g_ceph_context, CEPH_CRYPTO_AES);
170 cout << key << std::endl;
171 return 0;
172 }
173
174 // keyring --------
175 bool modified = false;
11fdf7f2 176 bool added_entity = false;
7c673cae
FG
177 KeyRing keyring;
178
179 bufferlist bl;
180 int r = 0;
181 if (create_keyring) {
182 cout << "creating " << fn << std::endl;
183 modified = true;
184 } else {
185 std::string err;
186 r = bl.read_file(fn.c_str(), &err);
187 if (r >= 0) {
188 try {
11fdf7f2
TL
189 auto iter = bl.cbegin();
190 decode(keyring, iter);
7c673cae
FG
191 } catch (const buffer::error &err) {
192 cerr << "error reading file " << fn << std::endl;
193 exit(1);
194 }
195 } else {
196 cerr << "can't open " << fn << ": " << err << std::endl;
197 exit(1);
198 }
199 }
200
201 // Validate that "name" actually has an existing key in this keyring if we
202 // have not given gen-key or add-key options
203 if (!gen_key && add_key.empty() && !caps.empty()) {
204 CryptoKey key;
205 if (!keyring.get_secret(ename, key)) {
206 cerr << "can't find existing key for " << ename
207 << " and neither gen-key nor add-key specified" << std::endl;
208 exit(1);
209 }
210 }
211
212 // write commands
213 if (!import_keyring.empty()) {
214 KeyRing other;
215 bufferlist obl;
216 std::string err;
217 int r = obl.read_file(import_keyring.c_str(), &err);
218 if (r >= 0) {
219 try {
11fdf7f2
TL
220 auto iter = obl.cbegin();
221 decode(other, iter);
7c673cae
FG
222 } catch (const buffer::error &err) {
223 cerr << "error reading file " << import_keyring << std::endl;
224 exit(1);
225 }
226
227 cout << "importing contents of " << import_keyring << " into " << fn << std::endl;
228 //other.print(cout);
229 keyring.import(g_ceph_context, other);
230 modified = true;
231 } else {
232 cerr << "can't open " << import_keyring << ": " << err << std::endl;
233 exit(1);
234 }
235 }
236 if (gen_key) {
237 EntityAuth eauth;
238 eauth.key.create(g_ceph_context, CEPH_CRYPTO_AES);
239 keyring.add(ename, eauth);
240 modified = true;
241 }
242 if (!add_key.empty()) {
243 EntityAuth eauth;
244 try {
245 eauth.key.decode_base64(add_key);
246 } catch (const buffer::error &err) {
247 cerr << "can't decode key '" << add_key << "'" << std::endl;
248 exit(1);
249 }
250 keyring.add(ename, eauth);
251 modified = true;
11fdf7f2
TL
252 cout << "added entity " << ename << " " << eauth << std::endl;
253 added_entity = true;
7c673cae
FG
254 }
255 if (!caps_fn.empty()) {
256 ConfFile cf;
9f95a23c 257 if (cf.parse_file(caps_fn, &cerr) != 0) {
7c673cae
FG
258 cerr << "could not parse caps file " << caps_fn << std::endl;
259 exit(1);
260 }
7c673cae
FG
261 map<string, bufferlist> caps;
262 const char *key_names[] = { "mon", "osd", "mds", "mgr", NULL };
263 for (int i=0; key_names[i]; i++) {
264 std::string val;
265 if (cf.read("global", key_names[i], val) == 0) {
266 bufferlist bl;
11fdf7f2 267 encode(val, bl);
7c673cae
FG
268 string s(key_names[i]);
269 caps[s] = bl;
270 }
271 }
272 keyring.set_caps(ename, caps);
273 modified = true;
274 }
275 if (!caps.empty()) {
276 keyring.set_caps(ename, caps);
277 modified = true;
278 }
11fdf7f2
TL
279 if (added_entity && caps.size() > 0) {
280 cout << "added " << caps.size() << " caps to entity " << ename << std::endl;
7c673cae
FG
281 }
282
283 // read commands
284 if (list) {
285 try {
286 keyring.print(cout);
287 } catch (ceph::buffer::end_of_buffer &eob) {
288 cout << "Exception (end_of_buffer) in print(), exit." << std::endl;
289 exit(1);
290 }
291 }
292 if (print_key) {
293 CryptoKey key;
294 if (keyring.get_secret(ename, key)) {
295 cout << key << std::endl;
296 } else {
297 cerr << "entity " << ename << " not found" << std::endl;
298 exit(1);
299 }
300 }
301
302 // write result?
303 if (modified) {
304 bufferlist bl;
305 keyring.encode_plaintext(bl);
94b18763 306 r = bl.write_file(fn.c_str(), mode);
7c673cae
FG
307 if (r < 0) {
308 cerr << "could not write " << fn << std::endl;
309 exit(1);
310 }
311 //cout << "wrote " << bl.length() << " bytes to " << fn << std::endl;
312 }
313 return 0;
314}