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(globish const & pattern,
135 vector<rsa_keypair_id> & priv)
136{
137 maybe_read_key_dir();
138 priv.clear();
139 for (map<rsa_keypair_id, keypair>::const_iterator
140 i = keys.begin(); i != keys.end(); ++i)
141 if (pattern.matches((i->first)()))
142 priv.push_back(i->first);
143}
144
145void
146key_store::get_key_ids(vector<rsa_keypair_id> & priv)
147{
148 maybe_read_key_dir();
149 priv.clear();
150 for (map<rsa_keypair_id, keypair>::const_iterator
151 i = keys.begin(); i != keys.end(); ++i)
152 priv.push_back(i->first);
153}
154
155bool
156key_store::key_pair_exists(rsa_keypair_id const & ident)
157{
158 maybe_read_key_dir();
159 return keys.find(ident) != keys.end();
160}
161
162void
163key_store::get_key_pair(rsa_keypair_id const & ident,
164 keypair & kp)
165{
166 maybe_read_key_dir();
167 map<rsa_keypair_id, keypair>::const_iterator i = keys.find(ident);
168 I(i != keys.end());
169 kp = i->second;
170}
171
172void
173key_store::get_key_file(rsa_keypair_id const & ident,
174 system_path & file)
175{
176 // filename is the keypair id, except that some characters can't be put in
177 // filenames (especially on windows).
178 string leaf = ident();
179 for (unsigned int i = 0; i < leaf.size(); ++i)
180 if (leaf.at(i) == '+')
181 leaf.at(i) = '_';
182
183 file = key_dir / path_component(leaf);
184}
185
186void
187key_store::write_key(rsa_keypair_id const & ident)
188{
189 keypair kp;
190 get_key_pair(ident, kp);
191 ostringstream oss;
192 packet_writer pw(oss);
193 pw.consume_key_pair(ident, kp);
194 data dat(oss.str());
195 system_path file;
196 get_key_file(ident, file);
197
198 // Make sure the private key is not readable by anyone other than the user.
199 L(FL("writing key '%s' to file '%s' in dir '%s'") % ident % file % key_dir);
200 write_data_userprivate(file, dat, key_dir);
201}
202
203bool
204key_store::put_key_pair(rsa_keypair_id const & ident,
205 keypair const & kp)
206{
207 bool newkey = put_key_pair_memory(ident, kp);
208 if (newkey)
209 write_key(ident);
210 return newkey;
211}
212
213bool
214key_store::put_key_pair_memory(rsa_keypair_id const & ident,
215 keypair const & kp)
216{
217 maybe_read_key_dir();
218 L(FL("putting key pair '%s'") % ident);
219 pair<map<rsa_keypair_id, keypair>::iterator, bool> res;
220 res = keys.insert(make_pair(ident, kp));
221 if (res.second)
222 {
223 hexenc<id> hash;
224 key_hash_code(ident, kp.pub, hash);
225 I(hashes.insert(make_pair(hash, ident)).second);
226 return true;
227 }
228 else
229 {
230 E(keys_match(ident, res.first->second.pub, ident, kp.pub),
231 F("Cannot store key '%s': a different key by that name exists.")
232 % ident);
233 L(FL("skipping existing key pair %s") % ident);
234 return false;
235 }
236}
237
238void
239key_store::delete_key(rsa_keypair_id const & ident)
240{
241 maybe_read_key_dir();
242 map<rsa_keypair_id, keypair>::iterator i = keys.find(ident);
243 if (i != keys.end())
244 {
245 hexenc<id> hash;
246 key_hash_code(ident, i->second.pub, hash);
247 map<hexenc<id>, rsa_keypair_id>::iterator j = hashes.find(hash);
248 I(j != hashes.end());
249 hashes.erase(j);
250 keys.erase(i);
251 }
252 system_path file;
253 get_key_file(ident, file);
254 delete_file(file);
255}
256
257// Local Variables:
258// mode: C++
259// fill-column: 76
260// c-file-style: "gnu"
261// indent-tabs-mode: nil
262// End:
263// 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