1 /* keys.c --- Functions for managing keys sets, and keys stored in files.
2 * Copyright (C) 2002-2013 Simon Josefsson
3 *
4 * This file is part of Shishi.
5 *
6 * Shishi is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Shishi is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Shishi; if not, see http://www.gnu.org/licenses or write
18 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 * Floor, Boston, MA 02110-1301, USA
20 *
21 */
22
23 #include "internal.h"
24
25 struct Shishi_keys
26 {
27 Shishi *handle;
28 Shishi_key **keys;
29 int nkeys;
30 };
31
32 /**
33 * shishi_keys:
34 * @handle: shishi handle as allocated by shishi_init().
35 * @keys: output pointer to newly allocated keys handle.
36 *
37 * Get a new key set handle.
38 *
39 * Return value: Returns %SHISHI_OK iff successful.
40 **/
41 int
shishi_keys(Shishi * handle,Shishi_keys ** keys)42 shishi_keys (Shishi * handle, Shishi_keys ** keys)
43 {
44 *keys = xmalloc (sizeof (**keys));
45
46 (*keys)->handle = handle;
47 (*keys)->keys = NULL;
48 (*keys)->nkeys = 0;
49
50 return SHISHI_OK;
51 }
52
53 /**
54 * shishi_keys_done:
55 * @keys: key set handle as allocated by shishi_keys().
56 *
57 * Deallocates all resources associated with key set. The key set
58 * handle must not be used in calls to other shishi_keys_*() functions
59 * after this.
60 **/
61 void
shishi_keys_done(Shishi_keys ** keys)62 shishi_keys_done (Shishi_keys ** keys)
63 {
64 size_t i;
65
66 if (!keys || !*keys)
67 return;
68
69 if ((*keys)->nkeys > 0)
70 for (i = (*keys)->nkeys; i > 0; i--)
71 shishi_key_done ((*keys)->keys[i - 1]);
72
73 free ((*keys)->keys);
74 free (*keys);
75
76 *keys = NULL;
77
78 return;
79 }
80
81 /**
82 * shishi_keys_size:
83 * @keys: key set handle as allocated by shishi_keys().
84 *
85 * Get size of key set.
86 *
87 * Return value: Returns number of keys stored in key set.
88 **/
89 int
shishi_keys_size(Shishi_keys * keys)90 shishi_keys_size (Shishi_keys * keys)
91 {
92 return keys->nkeys;
93 }
94
95 /**
96 * shishi_keys_nth:
97 * @keys: key set handle as allocated by shishi_keys().
98 * @keyno: integer indicating requested key in key set.
99 *
100 * Get the n:th ticket in key set.
101 *
102 * Return value: Returns a key handle to the keyno:th key in the key
103 * set, or NULL if @keys is invalid or @keyno is out of bounds. The
104 * first key is @keyno 0, the second key @keyno 1, and so on.
105 **/
106 const Shishi_key *
shishi_keys_nth(Shishi_keys * keys,int keyno)107 shishi_keys_nth (Shishi_keys * keys, int keyno)
108 {
109 if (keys == NULL || keyno >= keys->nkeys)
110 return NULL;
111
112 return keys->keys[keyno];
113 }
114
115 /**
116 * shishi_keys_remove:
117 * @keys: key set handle as allocated by shishi_keys().
118 * @keyno: key number of key in the set to remove. The first
119 * key is key number 0.
120 *
121 * Remove a key, indexed by @keyno, in given key set.
122 **/
123 void
shishi_keys_remove(Shishi_keys * keys,int keyno)124 shishi_keys_remove (Shishi_keys * keys, int keyno)
125 {
126 shishi_key_done (keys->keys[keyno]);
127
128 if (keyno < keys->nkeys)
129 memmove (&keys->keys[keyno], &keys->keys[keyno + 1],
130 sizeof (*keys->keys) * (keys->nkeys - keyno - 1));
131
132 --keys->nkeys;
133
134 keys->keys = xrealloc (keys->keys, sizeof (*keys->keys) * keys->nkeys);
135 }
136
137 /**
138 * shishi_keys_add:
139 * @keys: key set handle as allocated by shishi_keys().
140 * @key: key to be added to key set.
141 *
142 * Add a key to the key set. A deep copy of the key is stored, so
143 * changing @key, or deallocating it, will not modify the value stored
144 * in the key set.
145 *
146 * Return value: Returns %SHISHI_OK iff successful.
147 **/
148 int
shishi_keys_add(Shishi_keys * keys,Shishi_key * key)149 shishi_keys_add (Shishi_keys * keys, Shishi_key * key)
150 {
151 int rc;
152
153 if (!key)
154 return SHISHI_INVALID_KEY;
155
156 keys->nkeys++;
157
158 keys->keys = xrealloc (keys->keys, sizeof (*keys->keys) * keys->nkeys);
159
160 rc = shishi_key (keys->handle, &(keys->keys[keys->nkeys - 1]));
161 if (rc != SHISHI_OK)
162 return rc;
163
164 shishi_key_copy (keys->keys[keys->nkeys - 1], key);
165
166 return SHISHI_OK;
167 }
168
169 /**
170 * shishi_keys_print:
171 * @keys: key set to print.
172 * @fh: file handle, open for writing, to print keys to.
173 *
174 * Print all keys in set using shishi_key_print.
175 *
176 * Returns: Returns %SHISHI_OK on success.
177 **/
178 int
shishi_keys_print(Shishi_keys * keys,FILE * fh)179 shishi_keys_print (Shishi_keys * keys, FILE * fh)
180 {
181 int rc;
182 int i;
183
184 for (i = 0; i < keys->nkeys; i++)
185 {
186 rc = shishi_key_print (keys->handle, fh, shishi_keys_nth (keys, i));
187 if (rc != SHISHI_OK)
188 return rc;
189
190 fprintf (fh, "\n");
191 }
192
193 return SHISHI_OK;
194 }
195
196 /**
197 * shishi_keys_to_file:
198 * @handle: shishi handle as allocated by shishi_init().
199 * @filename: filename to append key to.
200 * @keys: set of keys to print.
201 *
202 * Print an ASCII representation of a key structure to a file, for
203 * each key in the key set. The file is appended to if it exists.
204 * See shishi_key_print() for the format of the output.
205 *
206 * Return value: Returns %SHISHI_OK iff successful.
207 **/
208 int
shishi_keys_to_file(Shishi * handle,const char * filename,Shishi_keys * keys)209 shishi_keys_to_file (Shishi * handle,
210 const char *filename, Shishi_keys * keys)
211 {
212 FILE *fh;
213 int res;
214
215 if (VERBOSE (handle))
216 printf (_("Writing KEYS to %s...\n"), filename);
217
218 fh = fopen (filename, "a");
219 if (fh == NULL)
220 return SHISHI_FOPEN_ERROR;
221
222 res = shishi_keys_print (keys, fh);
223 if (res != SHISHI_OK)
224 return res;
225
226 res = fclose (fh);
227 if (res != 0)
228 return SHISHI_IO_ERROR;
229
230 if (VERBOSE (handle))
231 printf (_("Writing KEYS to %s...done\n"), filename);
232
233 return SHISHI_OK;
234 }
235
236 /**
237 * shishi_keys_from_file:
238 * @keys: key set handle as allocated by shishi_keys().
239 * @filename: filename to read keys from.
240 *
241 * Read zero or more keys from file @filename and append them to the
242 * keyset @keys. See shishi_key_print() for the format of the input.
243 *
244 * Return value: Returns %SHISHI_OK iff successful.
245 *
246 * Since: 0.0.42
247 **/
248 int
shishi_keys_from_file(Shishi_keys * keys,const char * filename)249 shishi_keys_from_file (Shishi_keys * keys, const char *filename)
250 {
251 FILE *fh;
252 int res;
253
254 fh = fopen (filename, "r");
255 if (fh == NULL)
256 return SHISHI_FOPEN_ERROR;
257
258 res = SHISHI_OK;
259 while (!feof (fh))
260 {
261 Shishi_key *key = NULL;
262
263 res = shishi_key_parse (keys->handle, fh, &key);
264 if (res != SHISHI_OK || key == NULL)
265 break;
266
267 if (VERBOSENOISE (keys->handle))
268 {
269 printf ("Read key:\n");
270 shishi_key_print (keys->handle, stdout, key);
271 }
272
273 res = shishi_keys_add (keys, key);
274
275 shishi_key_done (key);
276 key = NULL;
277 }
278
279 res = fclose (fh);
280 if (res != 0)
281 return SHISHI_IO_ERROR;
282
283 return SHISHI_OK;
284 }
285
286 /**
287 * shishi_keys_for_serverrealm_in_file
288 * @handle: Shishi library handle create by shishi_init().
289 * @filename: file to read keys from.
290 * @server: server name to get key for.
291 * @realm: realm of server to get key for.
292 *
293 * Get keys that match specified @server and @realm from the key set
294 * file @filename.
295 *
296 * Return value: Returns the key for specific server and realm, read
297 * from the indicated file, or NULL if no key could be found or an
298 * error encountered.
299 **/
300 Shishi_key *
shishi_keys_for_serverrealm_in_file(Shishi * handle,const char * filename,const char * server,const char * realm)301 shishi_keys_for_serverrealm_in_file (Shishi * handle,
302 const char *filename,
303 const char *server, const char *realm)
304 {
305 Shishi_key *key = NULL;
306 FILE *fh;
307 int res;
308
309 fh = fopen (filename, "r");
310 if (fh == NULL)
311 return NULL;
312
313 res = SHISHI_OK;
314 while (!feof (fh))
315 {
316 res = shishi_key_parse (handle, fh, &key);
317 if (res != SHISHI_OK || key == NULL)
318 break;
319
320 if (VERBOSENOISE (handle))
321 {
322 printf ("Read key:\n");
323 shishi_key_print (handle, stdout, key);
324 }
325
326 if ((!server ||
327 (shishi_key_principal (key) &&
328 strcmp (server, shishi_key_principal (key)) == 0)) &&
329 (!realm ||
330 (shishi_key_realm (key) &&
331 strcmp (realm, shishi_key_realm (key)) == 0)))
332 break;
333
334 shishi_key_done (key);
335 key = NULL;
336 }
337
338 res = fclose (fh);
339 if (res != 0)
340 return NULL;
341
342 return key;
343 }
344
345 /**
346 * shishi_keys_for_server_in_file
347 * @handle: Shishi library handle create by shishi_init().
348 * @filename: file to read keys from.
349 * @server: server name to get key for.
350 *
351 * Get key for specified @server from @filename.
352 *
353 * Return value: Returns the key for specific server, read from the
354 * indicated file, or NULL if no key could be found or an error
355 * encountered.
356 **/
357 Shishi_key *
shishi_keys_for_server_in_file(Shishi * handle,const char * filename,const char * server)358 shishi_keys_for_server_in_file (Shishi * handle,
359 const char *filename, const char *server)
360 {
361 return shishi_keys_for_serverrealm_in_file (handle, filename, server, NULL);
362 }
363
364 /**
365 * shishi_keys_for_localservicerealm_in_file:
366 * @handle: Shishi library handle create by shishi_init().
367 * @filename: file to read keys from.
368 * @service: service to get key for.
369 * @realm: realm of server to get key for, or NULL for default realm.
370 *
371 * Get key for specified @service and @realm from @filename.
372 *
373 * Return value: Returns the key for the server
374 * "SERVICE/HOSTNAME@REALM" (where HOSTNAME is the current system's
375 * hostname), read from the default host keys file (see
376 * shishi_hostkeys_default_file()), or NULL if no key could be found
377 * or an error encountered.
378 **/
379 Shishi_key *
shishi_keys_for_localservicerealm_in_file(Shishi * handle,const char * filename,const char * service,const char * realm)380 shishi_keys_for_localservicerealm_in_file (Shishi * handle,
381 const char *filename,
382 const char *service,
383 const char *realm)
384 {
385 char *hostname;
386 char *server;
387 Shishi_key *key;
388
389 hostname = xgethostname ();
390
391 asprintf (&server, "%s/%s", service, hostname);
392
393 key = shishi_keys_for_serverrealm_in_file (handle, filename, server, realm);
394
395 free (server);
396 free (hostname);
397
398 return key;
399 }
400