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