]>
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 | ||
25 | void 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 | ||
53 | int 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 | } |