monotone

monotone Mtn Source Tree

Root/key_store.cc

1#include "base.hh"
2#include <sstream>
3
4#include "key_store.hh"
5#include "file_io.hh"
6#include "packet.hh"
7#include "keys.hh"
8#include "globish.hh"
9#include "app_state.hh"
10
11using std::make_pair;
12using std::istringstream;
13using std::map;
14using std::ostringstream;
15using std::pair;
16using std::string;
17using std::vector;
18
19namespace
20{
21 struct keyreader : public packet_consumer
22 {
23 key_store & ks;
24
25 keyreader(key_store & k): ks(k) {}
26 virtual void consume_file_data(file_id const & ident,
27 file_data const & dat)
28 {E(false, F("Extraneous data in key store."));}
29 virtual void consume_file_delta(file_id const & id_old,
30 file_id const & id_new,
31 file_delta const & del)
32 {E(false, F("Extraneous data in key store."));}
33
34 virtual void consume_revision_data(revision_id const & ident,
35 revision_data const & dat)
36 {E(false, F("Extraneous data in key store."));}
37 virtual void consume_revision_cert(revision<cert> const & t)
38 {E(false, F("Extraneous data in key store."));}
39
40
41 virtual void consume_public_key(rsa_keypair_id const & ident,
42 base64< rsa_pub_key > const & k)
43 {E(false, F("Extraneous data in key store."));}
44
45 virtual void consume_key_pair(rsa_keypair_id const & ident,
46 keypair const & kp)
47 {
48 L(FL("reading key pair '%s' from key store") % ident);
49
50 E(ks.put_key_pair_memory(ident, kp),
51 F("Key store has multiple keys with id '%s'.") % ident);
52
53 L(FL("successfully read key pair '%s' from key store") % ident);
54 }
55 };
56}
57
58key_store::key_store(app_state & a): have_read(false), app(a)
59{
60}
61
62void
63key_store::set_key_dir(system_path const & kd)
64{
65 key_dir = kd;
66}
67
68system_path const &
69key_store::get_key_dir()
70{
71 return key_dir;
72}
73
74void
75key_store::read_key_dir()
76{
77 vector<path_component> key_files, dirs;
78 if (directory_exists(key_dir))
79 {
80 L(FL("reading key dir '%s'") % key_dir);
81 read_directory(key_dir, key_files, dirs);
82 }
83 else
84 L(FL("key dir '%s' does not exist") % key_dir);
85 keyreader kr(*this);
86 for (vector<path_component>::const_iterator i = key_files.begin();
87 i != key_files.end(); ++i)
88 {
89 L(FL("reading keys from file '%s'") % (*i));
90 data dat;
91 read_data(key_dir / *i, dat);
92 istringstream is(dat());
93 read_packets(is, kr, app);
94 }
95}
96
97void
98key_store::maybe_read_key_dir()
99{
100 if (have_read)
101 return;
102 have_read = true;
103 read_key_dir();
104}
105
106void
107key_store::ensure_in_database(rsa_keypair_id const & ident)
108{
109 maybe_read_key_dir();
110 map<rsa_keypair_id, keypair>::iterator i = keys.find(ident);
111
112 // if this object does not have the key, the database had better.
113 if (i == keys.end())
114 {
115 I(app.db.public_key_exists(ident));
116 return;
117 }
118
119 if (app.db.put_key(ident, i->second.pub))
120 L(FL("loaded public key '%s' into db") % ident);
121}
122
123bool
124key_store::try_ensure_in_db(hexenc<id> const & hash)
125{
126 map<hexenc<id>, rsa_keypair_id>::const_iterator i = hashes.find(hash);
127 if (i == hashes.end())
128 return false;
129 ensure_in_database(i->second);
130 return true;
131}
132
133void
134key_store::get_key_ids(string const & pattern,
135 vector<rsa_keypair_id> & priv)
136{
137 maybe_read_key_dir();
138 priv.clear();
139 globish inc(pattern);
140 if (pattern.empty())
141 inc = globish("*");
142 globish_matcher gm(inc, globish(""));
143 for (map<rsa_keypair_id, keypair>::const_iterator
144 i = keys.begin(); i != keys.end(); ++i)
145 {
146 if (gm((i->first)()))
147 priv.push_back(i->first);
148 }
149}
150
151void
152key_store::get_keys(vector<rsa_keypair_id> & priv)
153{
154 maybe_read_key_dir();
155 priv.clear();
156 for (map<rsa_keypair_id, keypair>::const_iterator
157 i = keys.begin(); i != keys.end(); ++i)
158 {
159 priv.push_back(i->first);
160 }
161}
162
163bool
164key_store::key_pair_exists(rsa_keypair_id const & ident)
165{
166 maybe_read_key_dir();
167 return keys.find(ident) != keys.end();
168}
169
170void
171key_store::get_key_pair(rsa_keypair_id const & ident,
172 keypair & kp)
173{
174 maybe_read_key_dir();
175 map<rsa_keypair_id, keypair>::const_iterator i = keys.find(ident);
176 I(i != keys.end());
177 kp = i->second;
178}
179
180void
181key_store::get_key_file(rsa_keypair_id const & ident,
182 system_path & file)
183{
184 // filename is the keypair id, except that some characters can't be put in
185 // filenames (especially on windows).
186 string leaf = ident();
187 for (unsigned int i = 0; i < leaf.size(); ++i)
188 if (leaf.at(i) == '+')
189 leaf.at(i) = '_';
190
191 file = key_dir / path_component(leaf);
192}
193
194void
195key_store::write_key(rsa_keypair_id const & ident)
196{
197 keypair kp;
198 get_key_pair(ident, kp);
199 ostringstream oss;
200 packet_writer pw(oss);
201 pw.consume_key_pair(ident, kp);
202 data dat(oss.str());
203 system_path file;
204 get_key_file(ident, file);
205
206 // Make sure the private key is not readable by anyone other than the user.
207 L(FL("writing key '%s' to file '%s' in dir '%s'") % ident % file % key_dir);
208 write_data_userprivate(file, dat, key_dir);
209}
210
211bool
212key_store::put_key_pair(rsa_keypair_id const & ident,
213 keypair const & kp)
214{
215 bool newkey = put_key_pair_memory(ident, kp);
216 if (newkey)
217 write_key(ident);
218 return newkey;
219}
220
221bool
222key_store::put_key_pair_memory(rsa_keypair_id const & ident,
223 keypair const & kp)
224{
225 maybe_read_key_dir();
226 L(FL("putting key pair '%s'") % ident);
227 pair<map<rsa_keypair_id, keypair>::iterator, bool> res;
228 res = keys.insert(make_pair(ident, kp));
229 if (res.second)
230 {
231 hexenc<id> hash;
232 key_hash_code(ident, kp.pub, hash);
233 I(hashes.insert(make_pair(hash, ident)).second);
234 return true;
235 }
236 else
237 {
238 E(keys_match(ident, res.first->second.pub, ident, kp.pub),
239 F("Cannot store key '%s'; a different key by that name exists.")
240 % ident);
241 L(FL("skipping existing key pair %s") % ident);
242 return false;
243 }
244}
245
246void
247key_store::delete_key(rsa_keypair_id const & ident)
248{
249 maybe_read_key_dir();
250 map<rsa_keypair_id, keypair>::iterator i = keys.find(ident);
251 if (i != keys.end())
252 {
253 hexenc<id> hash;
254 key_hash_code(ident, i->second.pub, hash);
255 map<hexenc<id>, rsa_keypair_id>::iterator j = hashes.find(hash);
256 I(j != hashes.end());
257 hashes.erase(j);
258 keys.erase(i);
259 }
260 system_path file;
261 get_key_file(ident, file);
262 delete_file(file);
263}
264
265// Local Variables:
266// mode: C++
267// fill-column: 76
268// c-file-style: "gnu"
269// indent-tabs-mode: nil
270// End:
271// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status