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