1
2/*
3 * Licensed Materials - Property of IBM
4 *
5 * trousers - An open source TCG Software Stack
6 *
7 * (C) Copyright International Business Machines Corp. 2004-2006
8 *
9 */
10
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <unistd.h>
16#include <errno.h>
17#include <sys/types.h>
18#include <sys/file.h>
19#include <sys/stat.h>
20#if defined (HAVE_BYTEORDER_H)
21#include <sys/byteorder.h>
22#elif defined (HTOLE_DEFINED)
23#ifdef __NetBSD__
24#include <sys/endian.h>
25#else
26#include <endian.h>
27#endif
28#define LE_16 htole16
29#define LE_32 htole32
30#define LE_64 htole64
31#else
32#define LE_16(x) (x)
33#define LE_32(x) (x)
34#define LE_64(x) (x)
35#endif
36#include <assert.h>
37#include <fcntl.h>
38#include <limits.h>
39
40#include "trousers/tss.h"
41#include "trousers_types.h"
42#include "tcsps.h"
43#include "tcs_tsp.h"
44#include "tcs_utils.h"
45#include "capabilities.h"
46#include "tcslog.h"
47#include "tcsd_wrap.h"
48#include "tcsd.h"
49
50int system_ps_fd = -1;
51MUTEX_DECLARE(disk_cache_lock);
52
53static struct flock fl;
54
55int
56get_file()
57{
58	int rc;
59	/* check the global file handle first.  If it exists, lock it and return */
60	if (system_ps_fd != -1) {
61		int rc = 0;
62
63		fl.l_type = F_WRLCK;
64		if ((rc = fcntl(system_ps_fd, F_SETLKW, &fl))) {
65			LogError("failed to get system PS lock: %s", strerror(errno));
66			return -1;
67		}
68
69		return system_ps_fd;
70	}
71
72	/* open and lock the file */
73	system_ps_fd = open(tcsd_options.system_ps_file, O_CREAT|O_RDWR, 0600);
74	if (system_ps_fd < 0) {
75		LogError("system PS: open() of %s failed: %s",
76				tcsd_options.system_ps_file, strerror(errno));
77		return -1;
78	}
79
80	fl.l_type = F_WRLCK;
81	if ((rc = fcntl(system_ps_fd, F_SETLKW, &fl))) {
82		LogError("failed to get system PS lock of file %s: %s",
83			tcsd_options.system_ps_file, strerror(errno));
84		return -1;
85	}
86
87	return system_ps_fd;
88}
89
90int
91put_file(int fd)
92{
93	int rc = 0;
94	/* release the file lock */
95
96	fl.l_type = F_UNLCK;
97	if ((rc = fcntl(fd, F_SETLKW, &fl))) {
98		LogError("failed to unlock system PS file: %s",
99			strerror(errno));
100		return -1;
101	}
102
103	return rc;
104}
105
106void
107close_file(int fd)
108{
109	close(fd);
110	system_ps_fd = -1;
111}
112
113TSS_RESULT
114psfile_get_parent_uuid_by_uuid(int fd, TSS_UUID *uuid, TSS_UUID *ret_uuid)
115{
116        int rc;
117        UINT32 file_offset = 0;
118        struct key_disk_cache *tmp;
119
120        MUTEX_LOCK(disk_cache_lock);
121        tmp = key_disk_cache_head;
122
123        while (tmp) {
124                if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) || !(tmp->flags & CACHE_FLAG_VALID)) {
125                        tmp = tmp->next;
126                        continue;
127                }
128
129                /* jump to the location of the parent uuid */
130                file_offset = TSSPS_PARENT_UUID_OFFSET(tmp);
131
132                rc = lseek(fd, file_offset, SEEK_SET);
133                if (rc == ((off_t) - 1)) {
134                        LogError("lseek: %s", strerror(errno));
135                        MUTEX_UNLOCK(disk_cache_lock);
136                        return -1;
137                }
138
139                if ((rc = read_data(fd, ret_uuid, sizeof(TSS_UUID)))) {
140			LogError("%s", __FUNCTION__);
141                        MUTEX_UNLOCK(disk_cache_lock);
142                        return rc;
143                }
144
145                MUTEX_UNLOCK(disk_cache_lock);
146                return TSS_SUCCESS;
147        }
148        MUTEX_UNLOCK(disk_cache_lock);
149        /* key not found */
150        return -2;
151}
152
153/*
154 * return a key blob from PS given a uuid
155 */
156TSS_RESULT
157psfile_get_key_by_uuid(int fd, TSS_UUID *uuid, BYTE *ret_buffer, UINT16 *ret_buffer_size)
158{
159        int rc;
160        UINT32 file_offset = 0;
161        struct key_disk_cache *tmp;
162
163        MUTEX_LOCK(disk_cache_lock);
164        tmp = key_disk_cache_head;
165
166        while (tmp) {
167                if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) || !(tmp->flags & CACHE_FLAG_VALID)) {
168                        tmp = tmp->next;
169                        continue;
170                }
171
172                /* jump to the location of the key blob */
173                file_offset = TSSPS_BLOB_DATA_OFFSET(tmp);
174
175                rc = lseek(fd, file_offset, SEEK_SET);
176                if (rc == ((off_t) - 1)) {
177                        LogError("lseek: %s", strerror(errno));
178                        MUTEX_UNLOCK(disk_cache_lock);
179                        return TCSERR(TSS_E_INTERNAL_ERROR);
180                }
181
182                /* we found the key; file ptr is pointing at the blob */
183                if (*ret_buffer_size < tmp->blob_size) {
184                        /* not enough room */
185                        MUTEX_UNLOCK(disk_cache_lock);
186                        return TCSERR(TSS_E_FAIL);
187                }
188
189                if ((rc = read_data(fd, ret_buffer, tmp->blob_size))) {
190			LogError("%s", __FUNCTION__);
191                        MUTEX_UNLOCK(disk_cache_lock);
192                        return rc;
193                }
194		*ret_buffer_size = tmp->blob_size;
195		LogDebugUnrollKey(ret_buffer);
196                MUTEX_UNLOCK(disk_cache_lock);
197                return TSS_SUCCESS;
198        }
199        MUTEX_UNLOCK(disk_cache_lock);
200        /* key not found */
201        return TCSERR(TSS_E_FAIL);
202}
203
204/*
205 * return a key blob from PS given its cache entry. The disk cache must be
206 * locked by the caller.
207 */
208TSS_RESULT
209psfile_get_key_by_cache_entry(int fd, struct key_disk_cache *c, BYTE *ret_buffer,
210			  UINT16 *ret_buffer_size)
211{
212        int rc;
213        UINT32 file_offset = 0;
214
215	/* jump to the location of the key blob */
216	file_offset = TSSPS_BLOB_DATA_OFFSET(c);
217
218	rc = lseek(fd, file_offset, SEEK_SET);
219	if (rc == ((off_t) - 1)) {
220		LogError("lseek: %s", strerror(errno));
221		return TCSERR(TSS_E_INTERNAL_ERROR);
222	}
223
224	/* we found the key; file ptr is pointing at the blob */
225	if (*ret_buffer_size < c->blob_size) {
226		/* not enough room */
227		LogError("%s: Buf size too small. Needed %d bytes, passed %d", __FUNCTION__,
228				c->blob_size, *ret_buffer_size);
229		return TCSERR(TSS_E_INTERNAL_ERROR);
230	}
231
232	if ((rc = read_data(fd, ret_buffer, c->blob_size))) {
233		LogError("%s: error reading %d bytes", __FUNCTION__, c->blob_size);
234		return TCSERR(TSS_E_INTERNAL_ERROR);
235	}
236	*ret_buffer_size = c->blob_size;
237
238	return TSS_SUCCESS;
239}
240
241/*
242 * return the vendor data from PS given its cache entry. The disk cache must be
243 * locked by the caller.
244 */
245TSS_RESULT
246psfile_get_vendor_data(int fd, struct key_disk_cache *c, UINT32 *size, BYTE **data)
247{
248        int rc;
249        UINT32 file_offset;
250
251	/* jump to the location of the data */
252	file_offset = TSSPS_VENDOR_DATA_OFFSET(c);
253
254	rc = lseek(fd, file_offset, SEEK_SET);
255	if (rc == ((off_t) - 1)) {
256		LogError("lseek: %s", strerror(errno));
257		return TCSERR(TSS_E_INTERNAL_ERROR);
258	}
259
260	if ((*data = malloc(c->vendor_data_size)) == NULL) {
261		LogError("malloc of %u bytes failed", c->vendor_data_size);
262		return TCSERR(TSS_E_OUTOFMEMORY);
263	}
264
265	if ((rc = read_data(fd, *data, c->vendor_data_size))) {
266		LogError("%s: error reading %u bytes", __FUNCTION__, c->vendor_data_size);
267		free(*data);
268		*data = NULL;
269		return TCSERR(TSS_E_INTERNAL_ERROR);
270	}
271	*size = c->vendor_data_size;
272
273	return TSS_SUCCESS;
274}
275
276TSS_RESULT
277psfile_get_ps_type_by_uuid(int fd, TSS_UUID *uuid, UINT32 *ret_ps_type)
278{
279	struct key_disk_cache *tmp;
280
281	MUTEX_LOCK(disk_cache_lock);
282	tmp = key_disk_cache_head;
283
284        while (tmp) {
285		if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) ||
286		    !(tmp->flags & CACHE_FLAG_VALID)) {
287			tmp = tmp->next;
288			continue;
289                }
290
291		if (tmp->flags & CACHE_FLAG_PARENT_PS_SYSTEM) {
292			*ret_ps_type = TSS_PS_TYPE_SYSTEM;
293			goto done;
294		} else
295			break;
296        }
297
298	*ret_ps_type = TSS_PS_TYPE_USER;
299done:
300	MUTEX_UNLOCK(disk_cache_lock);
301	return TSS_SUCCESS;
302}
303
304TSS_RESULT
305psfile_is_pub_registered(int fd, TCPA_STORE_PUBKEY *pub, TSS_BOOL *is_reg)
306{
307        int rc;
308        UINT32 file_offset = 0;
309        struct key_disk_cache *tmp;
310	char tmp_buffer[2048];
311
312        MUTEX_LOCK(disk_cache_lock);
313        tmp = key_disk_cache_head;
314
315        while (tmp) {
316		/* if the key is of the wrong size or is invalid, try the next one */
317                if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) {
318                        tmp = tmp->next;
319                        continue;
320                }
321
322		/* we have a valid key with the same key size as the one we're looking for.
323		 * grab the pub key data off disk and compare it. */
324
325                /* jump to the location of the public key */
326                file_offset = TSSPS_PUB_DATA_OFFSET(tmp);
327
328                rc = lseek(fd, file_offset, SEEK_SET);
329                if (rc == ((off_t) - 1)) {
330                        LogError("lseek: %s", strerror(errno));
331                        MUTEX_UNLOCK(disk_cache_lock);
332                        return TCSERR(TSS_E_INTERNAL_ERROR);
333                }
334
335		DBG_ASSERT(tmp->pub_data_size < 2048);
336
337		/* read in the key */
338                if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) {
339			LogError("%s", __FUNCTION__);
340                        MUTEX_UNLOCK(disk_cache_lock);
341                        return rc;
342                }
343
344		/* do the compare */
345		if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) {
346			tmp = tmp->next;
347			continue;
348		}
349
350		/* the key matches, copy the uuid out */
351		*is_reg = TRUE;
352
353                MUTEX_UNLOCK(disk_cache_lock);
354                return TSS_SUCCESS;
355        }
356        MUTEX_UNLOCK(disk_cache_lock);
357        /* key not found */
358	*is_reg = FALSE;
359        return TSS_SUCCESS;
360}
361
362
363TSS_RESULT
364psfile_get_uuid_by_pub(int fd, TCPA_STORE_PUBKEY *pub, TSS_UUID **ret_uuid)
365{
366        int rc;
367        UINT32 file_offset = 0;
368        struct key_disk_cache *tmp;
369	char tmp_buffer[2048];
370
371        MUTEX_LOCK(disk_cache_lock);
372        tmp = key_disk_cache_head;
373
374        while (tmp) {
375		/* if the key is of the wrong size or is invalid, try the next one */
376                if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) {
377                        tmp = tmp->next;
378                        continue;
379                }
380
381		/* we have a valid key with the same key size as the one we're looking for.
382		 * grab the pub key data off disk and compare it. */
383
384                /* jump to the location of the public key */
385                file_offset = TSSPS_PUB_DATA_OFFSET(tmp);
386
387                rc = lseek(fd, file_offset, SEEK_SET);
388                if (rc == ((off_t) - 1)) {
389                        LogError("lseek: %s", strerror(errno));
390                        MUTEX_UNLOCK(disk_cache_lock);
391                        return TCSERR(TSS_E_INTERNAL_ERROR);
392                }
393
394		DBG_ASSERT(tmp->pub_data_size < 2048);
395
396		if (tmp->pub_data_size > sizeof(tmp_buffer)) {
397			LogError("Source buffer size too big! Size:  %d",
398				 tmp->pub_data_size);
399			MUTEX_UNLOCK(disk_cache_lock);
400			return TCSERR(TSS_E_INTERNAL_ERROR);
401		}
402		/* read in the key */
403                if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) {
404			LogError("%s", __FUNCTION__);
405                        MUTEX_UNLOCK(disk_cache_lock);
406                        return rc;
407                }
408
409		/* do the compare */
410		if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) {
411			tmp = tmp->next;
412			continue;
413		}
414
415		*ret_uuid = (TSS_UUID *)malloc(sizeof(TSS_UUID));
416		if (*ret_uuid == NULL) {
417			LogError("malloc of %zd bytes failed.", sizeof(TSS_UUID));
418                        MUTEX_UNLOCK(disk_cache_lock);
419			return TCSERR(TSS_E_OUTOFMEMORY);
420		}
421
422		/* the key matches, copy the uuid out */
423		memcpy(*ret_uuid, &tmp->uuid, sizeof(TSS_UUID));
424
425                MUTEX_UNLOCK(disk_cache_lock);
426                return TSS_SUCCESS;
427        }
428        MUTEX_UNLOCK(disk_cache_lock);
429        /* key not found */
430        return TCSERR(TSS_E_PS_KEY_NOTFOUND);
431}
432
433TSS_RESULT
434psfile_get_key_by_pub(int fd, TCPA_STORE_PUBKEY *pub, UINT32 *size, BYTE **ret_key)
435{
436        int rc;
437        UINT32 file_offset = 0;
438        struct key_disk_cache *tmp;
439	BYTE tmp_buffer[4096];
440
441        MUTEX_LOCK(disk_cache_lock);
442        tmp = key_disk_cache_head;
443
444        while (tmp) {
445		/* if the key is of the wrong size or is invalid, try the next one */
446                if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) {
447                        tmp = tmp->next;
448                        continue;
449                }
450
451		/* we have a valid key with the same key size as the one we're looking for.
452		 * grab the pub key data off disk and compare it. */
453
454                /* jump to the location of the public key */
455                file_offset = TSSPS_PUB_DATA_OFFSET(tmp);
456
457                rc = lseek(fd, file_offset, SEEK_SET);
458                if (rc == ((off_t) - 1)) {
459                        LogError("lseek: %s", strerror(errno));
460                        MUTEX_UNLOCK(disk_cache_lock);
461                        return TCSERR(TSS_E_INTERNAL_ERROR);
462                }
463
464		DBG_ASSERT(tmp->pub_data_size < 2048);
465		if (tmp->pub_data_size > sizeof(tmp_buffer)) {
466			LogError("Source buffer size too big! Size:  %d",
467				 tmp->pub_data_size);
468			MUTEX_UNLOCK(disk_cache_lock);
469			return TCSERR(TSS_E_INTERNAL_ERROR);
470		}
471
472		/* read in the key */
473                if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) {
474			LogError("%s", __FUNCTION__);
475                        MUTEX_UNLOCK(disk_cache_lock);
476                        return rc;
477                }
478
479		/* do the compare */
480		if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) {
481			tmp = tmp->next;
482			continue;
483		}
484
485                /* jump to the location of the key blob */
486                file_offset = TSSPS_BLOB_DATA_OFFSET(tmp);
487
488                rc = lseek(fd, file_offset, SEEK_SET);
489                if (rc == ((off_t) - 1)) {
490                        LogError("lseek: %s", strerror(errno));
491                        MUTEX_UNLOCK(disk_cache_lock);
492                        return TCSERR(TSS_E_INTERNAL_ERROR);
493                }
494
495		DBG_ASSERT(tmp->blob_size < 4096);
496		if (tmp->blob_size > sizeof(tmp_buffer)) {
497			LogError("Blob size greater than 4096! Size:  %d",
498				 tmp->blob_size);
499			MUTEX_UNLOCK(disk_cache_lock);
500			return TCSERR(TSS_E_INTERNAL_ERROR);
501		}
502
503		/* read in the key blob */
504                if ((rc = read_data(fd, tmp_buffer, tmp->blob_size))) {
505			LogError("%s", __FUNCTION__);
506                        MUTEX_UNLOCK(disk_cache_lock);
507                        return rc;
508                }
509
510		*ret_key = malloc(tmp->blob_size);
511		if (*ret_key == NULL) {
512			LogError("malloc of %d bytes failed.", tmp->blob_size);
513                        MUTEX_UNLOCK(disk_cache_lock);
514			return TCSERR(TSS_E_OUTOFMEMORY);
515		}
516
517		memcpy(*ret_key, tmp_buffer, tmp->blob_size);
518		*size = tmp->blob_size;
519
520                MUTEX_UNLOCK(disk_cache_lock);
521                return rc;
522        }
523        MUTEX_UNLOCK(disk_cache_lock);
524        /* key not found */
525        return -2;
526}
527
528/*
529 * disk store format:
530 *
531 * TrouSerS 0.2.0 and before:
532 * Version 0:                  cached?
533 * [UINT32   num_keys_on_disk]
534 * [TSS_UUID uuid0           ] yes
535 * [TSS_UUID uuid_parent0    ] yes
536 * [UINT16   pub_data_size0  ] yes
537 * [UINT16   blob_size0      ] yes
538 * [UINT16   cache_flags0    ] yes
539 * [BYTE[]   pub_data0       ]
540 * [BYTE[]   blob0           ]
541 * [...]
542 *
543 * TrouSerS 0.2.1+
544 * Version 1:                  cached?
545 * [BYTE     PS version = '\1']
546 * [UINT32   num_keys_on_disk ]
547 * [TSS_UUID uuid0            ] yes
548 * [TSS_UUID uuid_parent0     ] yes
549 * [UINT16   pub_data_size0   ] yes
550 * [UINT16   blob_size0       ] yes
551 * [UINT32   vendor_data_size0] yes
552 * [UINT16   cache_flags0     ] yes
553 * [BYTE[]   pub_data0        ]
554 * [BYTE[]   blob0            ]
555 * [BYTE[]   vendor_data0     ]
556 * [...]
557 *
558 */
559TSS_RESULT
560psfile_write_key(int fd,
561		TSS_UUID *uuid,
562		TSS_UUID *parent_uuid,
563		UINT32 *parent_ps,
564		BYTE *vendor_data,
565		UINT32 vendor_size,
566		BYTE *key_blob,
567		UINT16 key_blob_size)
568{
569	TSS_KEY key;
570	UINT16 pub_key_size, cache_flags = CACHE_FLAG_VALID;
571	UINT64 offset;
572	int rc = 0;
573
574	/* leaving the cache flag for parent ps type as 0 implies TSS_PS_TYPE_USER */
575	if (*parent_ps == TSS_PS_TYPE_SYSTEM)
576		cache_flags |= CACHE_FLAG_PARENT_PS_SYSTEM;
577
578	/* Unload the blob to get the public key */
579	offset = 0;
580	if ((rc = UnloadBlob_TSS_KEY(&offset, key_blob, &key)))
581		return rc;
582
583	pub_key_size = key.pubKey.keyLength;
584
585        if ((rc = write_key_init(fd, pub_key_size, key_blob_size, vendor_size)) < 0)
586                goto done;
587
588	/* offset now holds the number of bytes from the beginning of the file
589	 * the key will be stored at
590	 */
591	offset = rc;
592
593#ifdef TSS_DEBUG
594	if (offset == 0)
595		LogDebug("ERROR: key being written with offset 0!!");
596#endif
597
598	/* [TSS_UUID uuid0           ] yes */
599        if ((rc = write_data(fd, (void *)uuid, sizeof(TSS_UUID)))) {
600		LogError("%s", __FUNCTION__);
601                goto done;
602	}
603
604	/* [TSS_UUID uuid_parent0    ] yes */
605        if ((rc = write_data(fd, (void *)parent_uuid, sizeof(TSS_UUID)))) {
606		LogError("%s", __FUNCTION__);
607                goto done;
608	}
609
610	/* [UINT16   pub_data_size0  ] yes */
611	pub_key_size = LE_16(pub_key_size);
612        if ((rc = write_data(fd, &pub_key_size, sizeof(UINT16)))) {
613		LogError("%s", __FUNCTION__);
614                goto done;
615	}
616	/* Swap it back for later */
617	pub_key_size = LE_16(pub_key_size);
618
619	/* [UINT16   blob_size0      ] yes */
620	key_blob_size = LE_16(key_blob_size);
621        if ((rc = write_data(fd, &key_blob_size, sizeof(UINT16)))) {
622		LogError("%s", __FUNCTION__);
623                goto done;
624	}
625	/* Swap it back for later */
626	key_blob_size = LE_16(key_blob_size);
627
628	/* [UINT32   vendor_data_size0 ] yes */
629	vendor_size = LE_32(vendor_size);
630        if ((rc = write_data(fd, &vendor_size, sizeof(UINT32)))) {
631		LogError("%s", __FUNCTION__);
632                goto done;
633	}
634	/* Swap it back for later */
635	vendor_size = LE_32(vendor_size);
636
637	/* [UINT16   cache_flags0    ] yes */
638	cache_flags = LE_16(cache_flags);
639        if ((rc = write_data(fd, &cache_flags, sizeof(UINT16)))) {
640		LogError("%s", __FUNCTION__);
641                goto done;
642	}
643	/* Swap it back for later */
644	cache_flags = LE_16(cache_flags);
645
646	/* [BYTE[]   pub_data0       ] no */
647        if ((rc = write_data(fd, (void *)key.pubKey.key, pub_key_size))) {
648		LogError("%s", __FUNCTION__);
649                goto done;
650	}
651
652	/* [BYTE[]   blob0           ] no */
653        if ((rc = write_data(fd, (void *)key_blob, key_blob_size))) {
654		LogError("%s", __FUNCTION__);
655                goto done;
656	}
657
658	/* [BYTE[]   vendor_data0    ] no */
659	if (vendor_size > 0) {
660		if ((rc = write_data(fd, (void *)vendor_data, vendor_size))) {
661			LogError("%s", __FUNCTION__);
662			goto done;
663		}
664	}
665
666	if ((rc = cache_key((UINT32)offset, cache_flags, uuid, parent_uuid, pub_key_size,
667					key_blob_size, vendor_size)))
668                goto done;
669done:
670	destroy_key_refs(&key);
671
672        return rc;
673}
674
675TSS_RESULT
676psfile_remove_key(int fd, struct key_disk_cache *c)
677{
678        TSS_RESULT result;
679        UINT32 head_offset = 0, tail_offset, num_keys;
680	BYTE buf[4096];
681	struct stat stat_buf;
682	int rc, size = 0;
683
684	if ((rc = fstat(fd, &stat_buf)) != 0) {
685		LogError("fstat: %s", strerror(errno));
686		return TSS_E_INTERNAL_ERROR;
687	}
688
689	/* head_offset is the offset the beginning of the key */
690	head_offset = TSSPS_UUID_OFFSET(c);
691
692	/* tail_offset is the offset the beginning of the next key */
693	tail_offset = TSSPS_VENDOR_DATA_OFFSET(c) + c->vendor_data_size;
694
695	rc = lseek(fd, tail_offset, SEEK_SET);
696	if (rc == ((off_t) - 1)) {
697		LogError("lseek: %s", strerror(errno));
698		return TCSERR(TSS_E_INTERNAL_ERROR);
699	}
700
701	/* read in from tail, write out to head to fill the gap */
702	while ((rc = read(fd, buf, sizeof(buf))) > 0) {
703		size = rc;
704		tail_offset += size;
705
706		/* set the file pointer to where we want to write */
707		rc = lseek(fd, head_offset, SEEK_SET);
708		if (rc == ((off_t) - 1)) {
709			LogError("lseek: %s", strerror(errno));
710			return TCSERR(TSS_E_INTERNAL_ERROR);
711		}
712
713		/* write the data */
714		if ((result = write_data(fd, (void *)buf, size))) {
715			LogError("%s", __FUNCTION__);
716			return result;
717		}
718		head_offset += size;
719
720		/* set the file pointer to where we want to read in the next
721		 * loop */
722		rc = lseek(fd, tail_offset, SEEK_SET);
723		if (rc == ((off_t) - 1)) {
724			LogError("lseek: %s", strerror(errno));
725			return TCSERR(TSS_E_INTERNAL_ERROR);
726		}
727	}
728
729	if (rc < 0) {
730		LogError("read: %s", strerror(errno));
731		return TCSERR(TSS_E_INTERNAL_ERROR);
732	}
733
734	/* set the file pointer to where we want to write */
735	rc = lseek(fd, head_offset, SEEK_SET);
736	if (rc == ((off_t) - 1)) {
737		LogError("lseek: %s", strerror(errno));
738		return TCSERR(TSS_E_INTERNAL_ERROR);
739	}
740
741	/* head_offset now contains a pointer to where we want to truncate the
742	 * file. Zero out the old tail end of the file and truncate it. */
743
744	memset(buf, 0, sizeof(buf));
745
746	/* Zero out the old tail end of the file */
747	if ((result = write_data(fd, (void *)buf, tail_offset - head_offset))) {
748		LogError("%s", __FUNCTION__);
749		return result;
750	}
751
752	if ((rc = ftruncate(fd, head_offset)) < 0) {
753		LogError("ftruncate: %s", strerror(errno));
754		return TCSERR(TSS_E_INTERNAL_ERROR);
755	}
756
757	/* we succeeded in removing a key from the disk. Decrement the number
758	 * of keys in the file */
759	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
760	if (rc == ((off_t) - 1)) {
761		LogError("lseek: %s", strerror(errno));
762		return TCSERR(TSS_E_INTERNAL_ERROR);
763	}
764
765	rc = read(fd, &num_keys, sizeof(UINT32));
766	num_keys = LE_32(num_keys);
767	if (rc != sizeof(UINT32)) {
768		LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno));
769		return TCSERR(TSS_E_INTERNAL_ERROR);
770	}
771
772	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
773	if (rc == ((off_t) - 1)) {
774		LogError("lseek: %s", strerror(errno));
775		return TCSERR(TSS_E_INTERNAL_ERROR);
776	}
777
778	/* decrement, then write back out to disk */
779	num_keys--;
780
781	num_keys = LE_32(num_keys);
782	if ((result = write_data(fd, (void *)&num_keys, sizeof(UINT32)))) {
783		LogError("%s", __FUNCTION__);
784		return result;
785	}
786
787	return TSS_SUCCESS;
788}
789