]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/ceph_authtool.cc
bump version to 12.2.12-pve1
[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"
17#include "common/config.h"
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"
43 << " -u AUID, --set-uid AUID sets the auid (authenticated user id) for the\n"
44 << " specified entityname\n"
45 << " -a BASE64, --add-key BASE64 will add an encoded key to the keyring\n"
46 << " --cap SUBSYSTEM CAPABILITY will set the capability for given subsystem\n"
47 << " --caps CAPSFILE will set all of capabilities associated with a\n"
94b18763
FG
48 << " given key, for all subsystems\n"
49 << " --mode MODE will set the desired file mode to the keyring\n"
50 << " e.g: '0644', defaults to '0600'"
7c673cae
FG
51 << std::endl;
52 exit(1);
53}
54
55int main(int argc, const char **argv)
56{
57 vector<const char*> args;
58 argv_to_vec(argc, argv, args);
59 env_to_vec(args);
60
61 std::string add_key;
62 std::string caps_fn;
63 std::string import_keyring;
64 uint64_t auid = CEPH_AUTH_UID_DEFAULT;
65 map<string,bufferlist> caps;
66 std::string fn;
67
68 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
69 CODE_ENVIRONMENT_UTILITY,
70 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
71
72 bool gen_key = false;
73 bool gen_print_key = false;
74 bool list = false;
75 bool print_key = false;
76 bool create_keyring = false;
77 bool set_auid = false;
94b18763 78 int mode = 0600; // keyring file mode
7c673cae
FG
79 std::vector<const char*>::iterator i;
80
81 /* Handle options unique to ceph-authtool
82 * -n NAME, --name NAME is handled by global_init
83 * */
84 for (i = args.begin(); i != args.end(); ) {
85 std::string val;
86 if (ceph_argparse_double_dash(args, i)) {
87 break;
88 } else if (ceph_argparse_flag(args, i, "-g", "--gen-key", (char*)NULL)) {
89 gen_key = true;
90 } else if (ceph_argparse_flag(args, i, "--gen-print-key", (char*)NULL)) {
91 gen_print_key = true;
92 } else if (ceph_argparse_witharg(args, i, &val, "-a", "--add-key", (char*)NULL)) {
93 if (val.empty()) {
94 cerr << "Option --add-key requires an argument" << std::endl;
95 exit(1);
96 }
97 add_key = val;
98 } else if (ceph_argparse_flag(args, i, "-l", "--list", (char*)NULL)) {
99 list = true;
100 } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) {
101 caps_fn = val;
102 } else if (ceph_argparse_witharg(args, i, &val, "--cap", (char*)NULL)) {
103 std::string my_key = val;
104 if (i == args.end()) {
105 cerr << "must give two arguments to --cap: key and val." << std::endl;
106 exit(1);
107 }
108 std::string my_val = *i;
109 ++i;
110 ::encode(my_val, caps[my_key]);
111 } else if (ceph_argparse_flag(args, i, "-p", "--print-key", (char*)NULL)) {
112 print_key = true;
113 } else if (ceph_argparse_flag(args, i, "-C", "--create-keyring", (char*)NULL)) {
114 create_keyring = true;
115 } else if (ceph_argparse_witharg(args, i, &val, "--import-keyring", (char*)NULL)) {
116 import_keyring = val;
117 } else if (ceph_argparse_witharg(args, i, &val, "-u", "--set-uid", (char*)NULL)) {
118 std::string err;
119 auid = strict_strtoll(val.c_str(), 10, &err);
120 if (!err.empty()) {
121 cerr << "error parsing UID: " << err << std::endl;
122 exit(1);
123 }
124 set_auid = true;
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() ||
150 set_auid ||
151 print_key ||
152 create_keyring ||
153 !import_keyring.empty())) {
154 cerr << "no command specified" << std::endl;
155 usage();
156 }
157 if (gen_key && (!add_key.empty())) {
158 cerr << "can't both gen-key and add-key" << std::endl;
159 usage();
160 }
161
162 common_init_finish(g_ceph_context);
163 EntityName ename(g_conf->name);
164
165 // Enforce the use of gen-key or add-key when creating to avoid ending up
166 // with an "empty" key (key = AAAAAAAAAAAAAAAA)
167 if (create_keyring && !gen_key && add_key.empty() && !caps.empty()) {
168 cerr << "must specify either gen-key or add-key when creating" << std::endl;
169 usage();
170 }
171
172 if (gen_print_key) {
173 CryptoKey key;
174 key.create(g_ceph_context, CEPH_CRYPTO_AES);
175 cout << key << std::endl;
176 return 0;
177 }
178
179 // keyring --------
180 bool modified = false;
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 {
193 bufferlist::iterator iter = bl.begin();
194 ::decode(keyring, iter);
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 {
224 bufferlist::iterator iter = obl.begin();
225 ::decode(other, iter);
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;
256 cout << "added entity " << ename << " auth " << eauth << std::endl;
257 }
258 if (!caps_fn.empty()) {
259 ConfFile cf;
260 std::deque<std::string> parse_errors;
261 if (cf.parse_file(caps_fn, &parse_errors, &cerr) != 0) {
262 cerr << "could not parse caps file " << caps_fn << std::endl;
263 exit(1);
264 }
265 complain_about_parse_errors(g_ceph_context, &parse_errors);
266 map<string, bufferlist> caps;
267 const char *key_names[] = { "mon", "osd", "mds", "mgr", NULL };
268 for (int i=0; key_names[i]; i++) {
269 std::string val;
270 if (cf.read("global", key_names[i], val) == 0) {
271 bufferlist bl;
272 ::encode(val, bl);
273 string s(key_names[i]);
274 caps[s] = bl;
275 }
276 }
277 keyring.set_caps(ename, caps);
278 modified = true;
279 }
280 if (!caps.empty()) {
281 keyring.set_caps(ename, caps);
282 modified = true;
283 }
284 if (set_auid) {
285 keyring.set_uid(ename, auid);
286 modified = true;
287 }
288
289 // read commands
290 if (list) {
291 try {
292 keyring.print(cout);
293 } catch (ceph::buffer::end_of_buffer &eob) {
294 cout << "Exception (end_of_buffer) in print(), exit." << std::endl;
295 exit(1);
296 }
297 }
298 if (print_key) {
299 CryptoKey key;
300 if (keyring.get_secret(ename, key)) {
301 cout << key << std::endl;
302 } else {
303 cerr << "entity " << ename << " not found" << std::endl;
304 exit(1);
305 }
306 }
307
308 // write result?
309 if (modified) {
310 bufferlist bl;
311 keyring.encode_plaintext(bl);
94b18763 312 r = bl.write_file(fn.c_str(), mode);
7c673cae
FG
313 if (r < 0) {
314 cerr << "could not write " << fn << std::endl;
315 exit(1);
316 }
317 //cout << "wrote " << bl.length() << " bytes to " << fn << std::endl;
318 }
319 return 0;
320}