]>
Commit | Line | Data |
---|---|---|
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 |
25 | using std::map; |
26 | using std::string; | |
27 | using std::vector; | |
28 | using std::cerr; | |
29 | using std::cout; | |
30 | ||
7c673cae FG |
31 | void 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 | ||
59 | int 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 | } |