Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / tools / ceph_authtool.cc
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
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"
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"
48        << "                                given key, for all subsystems"
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);
57   env_to_vec(args);
58
59   std::string add_key;
60   std::string caps_fn;
61   std::string import_keyring;
62   uint64_t auid = CEPH_AUTH_UID_DEFAULT;
63   map<string,bufferlist> caps;
64   std::string fn;
65
66   auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
67                          CODE_ENVIRONMENT_UTILITY,
68                          CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
69
70   bool gen_key = false;
71   bool gen_print_key = false;
72   bool list = false;
73   bool print_key = false;
74   bool create_keyring = false;
75   bool set_auid = false;
76   std::vector<const char*>::iterator i;
77
78   /* Handle options unique to ceph-authtool
79    * -n NAME, --name NAME is handled by global_init
80    * */
81   for (i = args.begin(); i != args.end(); ) {
82     std::string val;
83     if (ceph_argparse_double_dash(args, i)) {
84       break;
85     } else if (ceph_argparse_flag(args, i, "-g", "--gen-key", (char*)NULL)) {
86       gen_key = true;
87     } else if (ceph_argparse_flag(args, i, "--gen-print-key", (char*)NULL)) {
88       gen_print_key = true;
89     } else if (ceph_argparse_witharg(args, i, &val, "-a", "--add-key", (char*)NULL)) {
90       if (val.empty()) {
91         cerr << "Option --add-key requires an argument" << std::endl;
92         exit(1);
93       }
94       add_key = val;
95     } else if (ceph_argparse_flag(args, i, "-l", "--list", (char*)NULL)) {
96       list = true;
97     } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) {
98       caps_fn = val;
99     } else if (ceph_argparse_witharg(args, i, &val, "--cap", (char*)NULL)) {
100       std::string my_key = val;
101       if (i == args.end()) {
102         cerr << "must give two arguments to --cap: key and val." << std::endl;
103         exit(1);
104       }
105       std::string my_val = *i;
106       ++i;
107       ::encode(my_val, caps[my_key]);
108     } else if (ceph_argparse_flag(args, i, "-p", "--print-key", (char*)NULL)) {
109       print_key = true;
110     } else if (ceph_argparse_flag(args, i, "-C", "--create-keyring", (char*)NULL)) {
111       create_keyring = true;
112     } else if (ceph_argparse_witharg(args, i, &val, "--import-keyring", (char*)NULL)) {
113       import_keyring = val;
114     } else if (ceph_argparse_witharg(args, i, &val, "-u", "--set-uid", (char*)NULL)) {
115       std::string err;
116       auid = strict_strtoll(val.c_str(), 10, &err);
117       if (!err.empty()) {
118         cerr << "error parsing UID: " << err << std::endl;
119         exit(1);
120       }
121       set_auid = true;
122     } else if (fn.empty()) {
123       fn = *i++;
124     } else {
125       cerr << argv[0] << ": unexpected '" << *i << "'" << std::endl;
126       usage();
127     }
128   }
129
130   if (fn.empty() && !gen_print_key) {
131     cerr << argv[0] << ": must specify filename" << std::endl;
132     usage();
133   }
134   if (!(gen_key ||
135         gen_print_key ||
136         !add_key.empty() ||
137         list ||
138         !caps_fn.empty() ||
139         !caps.empty() ||
140         set_auid ||
141         print_key ||
142         create_keyring ||
143         !import_keyring.empty())) {
144     cerr << "no command specified" << std::endl;
145     usage();
146   }
147   if (gen_key && (!add_key.empty())) {
148     cerr << "can't both gen-key and add-key" << std::endl;
149     usage();
150   }
151
152   common_init_finish(g_ceph_context);
153   EntityName ename(g_conf->name);
154
155   // Enforce the use of gen-key or add-key when creating to avoid ending up
156   // with an "empty" key (key = AAAAAAAAAAAAAAAA)
157   if (create_keyring && !gen_key && add_key.empty() && !caps.empty()) {
158     cerr << "must specify either gen-key or add-key when creating" << std::endl;
159     usage();
160   }
161
162   if (gen_print_key) {
163     CryptoKey key;
164     key.create(g_ceph_context, CEPH_CRYPTO_AES);
165     cout << key << std::endl;
166     return 0;
167   }
168
169   // keyring --------
170   bool modified = false;
171   KeyRing keyring;
172
173   bufferlist bl;
174   int r = 0;
175   if (create_keyring) {
176     cout << "creating " << fn << std::endl;
177     modified = true;
178   } else {
179     std::string err;
180     r = bl.read_file(fn.c_str(), &err);
181     if (r >= 0) {
182       try {
183         bufferlist::iterator iter = bl.begin();
184         ::decode(keyring, iter);
185       } catch (const buffer::error &err) {
186         cerr << "error reading file " << fn << std::endl;
187         exit(1);
188       }
189     } else {
190       cerr << "can't open " << fn << ": " << err << std::endl;
191       exit(1);
192     }
193   }
194
195   // Validate that "name" actually has an existing key in this keyring if we
196   // have not given gen-key or add-key options
197   if (!gen_key && add_key.empty() && !caps.empty()) {
198     CryptoKey key;
199     if (!keyring.get_secret(ename, key)) {
200       cerr << "can't find existing key for " << ename 
201            << " and neither gen-key nor add-key specified" << std::endl;
202       exit(1);
203     }
204   }
205
206   // write commands
207   if (!import_keyring.empty()) {
208     KeyRing other;
209     bufferlist obl;
210     std::string err;
211     int r = obl.read_file(import_keyring.c_str(), &err);
212     if (r >= 0) {
213       try {
214         bufferlist::iterator iter = obl.begin();
215         ::decode(other, iter);
216       } catch (const buffer::error &err) {
217         cerr << "error reading file " << import_keyring << std::endl;
218         exit(1);
219       }
220
221       cout << "importing contents of " << import_keyring << " into " << fn << std::endl;
222       //other.print(cout);
223       keyring.import(g_ceph_context, other);
224       modified = true;
225     } else {
226       cerr << "can't open " << import_keyring << ": " << err << std::endl;
227       exit(1);
228     }
229   }
230   if (gen_key) {
231     EntityAuth eauth;
232     eauth.key.create(g_ceph_context, CEPH_CRYPTO_AES);
233     keyring.add(ename, eauth);
234     modified = true;
235   }
236   if (!add_key.empty()) {
237     EntityAuth eauth;
238     try {
239       eauth.key.decode_base64(add_key);
240     } catch (const buffer::error &err) {
241       cerr << "can't decode key '" << add_key << "'" << std::endl;
242       exit(1);
243     }
244     keyring.add(ename, eauth);
245     modified = true;
246     cout << "added entity " << ename << " auth " << eauth << std::endl;
247   }
248   if (!caps_fn.empty()) {
249     ConfFile cf;
250     std::deque<std::string> parse_errors;
251     if (cf.parse_file(caps_fn, &parse_errors, &cerr) != 0) {
252       cerr << "could not parse caps file " << caps_fn << std::endl;
253       exit(1);
254     }
255     complain_about_parse_errors(g_ceph_context, &parse_errors);
256     map<string, bufferlist> caps;
257     const char *key_names[] = { "mon", "osd", "mds", "mgr", NULL };
258     for (int i=0; key_names[i]; i++) {
259       std::string val;
260       if (cf.read("global", key_names[i], val) == 0) {
261         bufferlist bl;
262         ::encode(val, bl);
263         string s(key_names[i]);
264         caps[s] = bl;
265       }
266     }
267     keyring.set_caps(ename, caps);
268     modified = true;
269   }
270   if (!caps.empty()) {
271     keyring.set_caps(ename, caps);
272     modified = true;
273   }
274   if (set_auid) {
275     keyring.set_uid(ename, auid);
276     modified = true;
277   }
278
279   // read commands
280   if (list) {
281     try {
282       keyring.print(cout);
283     } catch (ceph::buffer::end_of_buffer &eob) {
284       cout << "Exception (end_of_buffer) in print(), exit." << std::endl;
285       exit(1);
286     }
287   }
288   if (print_key) {
289     CryptoKey key;
290     if (keyring.get_secret(ename, key)) {
291       cout << key << std::endl;
292     } else {
293       cerr << "entity " << ename << " not found" << std::endl;
294       exit(1);
295     }
296   }
297
298   // write result?
299   if (modified) {
300     bufferlist bl;
301     keyring.encode_plaintext(bl);
302     r = bl.write_file(fn.c_str(), 0600);
303     if (r < 0) {
304       cerr << "could not write " << fn << std::endl;
305       exit(1);
306     }
307     //cout << "wrote " << bl.length() << " bytes to " << fn << std::endl;
308   }
309   return 0;
310 }