/src/gnupg/kbx/keybox-file.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* keybox-file.c - File operations |
2 | | * Copyright (C) 2001, 2003 Free Software Foundation, Inc. |
3 | | * |
4 | | * This file is part of GnuPG. |
5 | | * |
6 | | * GnuPG is free software; you can redistribute it and/or modify |
7 | | * it 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 | | * GnuPG is distributed in the hope that it will be useful, |
12 | | * but 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 this program; if not, see <https://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include <config.h> |
21 | | #include <stdlib.h> |
22 | | #include <stdio.h> |
23 | | #include <string.h> |
24 | | #include <errno.h> |
25 | | #include <time.h> |
26 | | |
27 | | #include "keybox-defs.h" |
28 | | |
29 | | |
30 | 68.2k | #define IMAGELEN_LIMIT (5*1024*1024) |
31 | | |
32 | | |
33 | | #if !defined(HAVE_FTELLO) && !defined(ftello) |
34 | | static off_t |
35 | | ftello (FILE *stream) |
36 | | { |
37 | | long int off; |
38 | | |
39 | | off = ftell (stream); |
40 | | if (off == -1) |
41 | | return (off_t)-1; |
42 | | return off; |
43 | | } |
44 | | #endif /* !defined(HAVE_FTELLO) && !defined(ftello) */ |
45 | | |
46 | | |
47 | | |
48 | | /* Read a block at the current position and return it in R_BLOB. |
49 | | R_BLOB may be NULL to simply skip the current block. */ |
50 | | int |
51 | | _keybox_read_blob (KEYBOXBLOB *r_blob, estream_t fp, int *skipped_deleted) |
52 | 136k | { |
53 | 136k | unsigned char *image; |
54 | 136k | size_t imagelen = 0; |
55 | 136k | int c1, c2, c3, c4, type; |
56 | 136k | int rc; |
57 | 136k | off_t off; |
58 | | |
59 | 136k | if (skipped_deleted) |
60 | 0 | *skipped_deleted = 0; |
61 | 136k | again: |
62 | 136k | if (r_blob) |
63 | 136k | *r_blob = NULL; |
64 | 136k | off = es_ftello (fp); |
65 | 136k | if (off == (off_t)-1) |
66 | 0 | return gpg_error_from_syserror (); |
67 | | |
68 | 136k | if ((c1 = es_getc (fp)) == EOF |
69 | 136k | || (c2 = es_getc (fp)) == EOF |
70 | 136k | || (c3 = es_getc (fp)) == EOF |
71 | 136k | || (c4 = es_getc (fp)) == EOF |
72 | 136k | || (type = es_getc (fp)) == EOF) |
73 | 68.1k | { |
74 | 68.1k | if ( c1 == EOF && !es_ferror (fp) ) |
75 | 68.1k | return -1; /* eof */ |
76 | 0 | if (!es_ferror (fp)) |
77 | 0 | return gpg_error (GPG_ERR_TOO_SHORT); |
78 | 0 | return gpg_error_from_syserror (); |
79 | 0 | } |
80 | | |
81 | 68.2k | imagelen = ((unsigned int) c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4; |
82 | 68.2k | if (imagelen < 5) |
83 | 0 | return gpg_error (GPG_ERR_TOO_SHORT); |
84 | | |
85 | 68.2k | if (!type) |
86 | 0 | { |
87 | | /* Special treatment for empty blobs. */ |
88 | 0 | if (es_fseek (fp, imagelen-5, SEEK_CUR)) |
89 | 0 | return gpg_error_from_syserror (); |
90 | 0 | if (skipped_deleted) |
91 | 0 | *skipped_deleted = 1; |
92 | 0 | goto again; |
93 | 0 | } |
94 | | |
95 | 68.2k | if (imagelen > IMAGELEN_LIMIT) /* Sanity check. */ |
96 | 0 | { |
97 | | /* Seek forward so that the caller may choose to ignore this |
98 | | record. */ |
99 | 0 | if (es_fseek (fp, imagelen-5, SEEK_CUR)) |
100 | 0 | return gpg_error_from_syserror (); |
101 | 0 | return gpg_error (GPG_ERR_TOO_LARGE); |
102 | 0 | } |
103 | | |
104 | 68.2k | if (!r_blob) |
105 | 9 | { |
106 | | /* This blob shall be skipped. */ |
107 | 9 | if (es_fseek (fp, imagelen-5, SEEK_CUR)) |
108 | 0 | return gpg_error_from_syserror (); |
109 | 9 | return 0; |
110 | 9 | } |
111 | | |
112 | 68.2k | image = xtrymalloc (imagelen); |
113 | 68.2k | if (!image) |
114 | 0 | return gpg_error_from_syserror (); |
115 | | |
116 | 68.2k | image[0] = c1; image[1] = c2; image[2] = c3; image[3] = c4; image[4] = type; |
117 | 68.2k | if (es_fread (image+5, imagelen-5, 1, fp) != 1) |
118 | 0 | { |
119 | 0 | gpg_error_t tmperr = gpg_error_from_syserror (); |
120 | 0 | xfree (image); |
121 | 0 | return tmperr; |
122 | 0 | } |
123 | | |
124 | 68.2k | rc = _keybox_new_blob (r_blob, image, imagelen, off); |
125 | 68.2k | if (rc) |
126 | 0 | xfree (image); |
127 | 68.2k | return rc; |
128 | 68.2k | } |
129 | | |
130 | | |
131 | | /* Write the block to the current file position */ |
132 | | int |
133 | | _keybox_write_blob (KEYBOXBLOB blob, estream_t fp, FILE *outfp) |
134 | 11 | { |
135 | 11 | const unsigned char *image; |
136 | 11 | size_t length; |
137 | | |
138 | 11 | image = _keybox_get_blob_image (blob, &length); |
139 | | |
140 | 11 | if (length > IMAGELEN_LIMIT) |
141 | 0 | return gpg_error (GPG_ERR_TOO_LARGE); |
142 | | |
143 | 11 | if (fp) |
144 | 11 | { |
145 | 11 | if (es_fwrite (image, length, 1, fp) != 1) |
146 | 0 | return gpg_error_from_syserror (); |
147 | 11 | } |
148 | 0 | else |
149 | 0 | { |
150 | 0 | if (fwrite (image, length, 1, outfp) != 1) |
151 | 0 | return gpg_error_from_syserror (); |
152 | 0 | } |
153 | | |
154 | 11 | return 0; |
155 | 11 | } |
156 | | |
157 | | |
158 | | /* Write a fresh header type blob. */ |
159 | | gpg_error_t |
160 | | _keybox_write_header_blob (estream_t fp, int for_openpgp) |
161 | 4 | { |
162 | 4 | unsigned char image[32]; |
163 | 4 | u32 val; |
164 | | |
165 | 4 | memset (image, 0, sizeof image); |
166 | | /* Length of this blob. */ |
167 | 4 | image[3] = 32; |
168 | | |
169 | 4 | image[4] = KEYBOX_BLOBTYPE_HEADER; |
170 | 4 | image[5] = 1; /* Version */ |
171 | 4 | if (for_openpgp) |
172 | 4 | image[7] = 0x02; /* OpenPGP data may be available. */ |
173 | | |
174 | 4 | memcpy (image+8, "KBXf", 4); |
175 | 4 | val = time (NULL); |
176 | | /* created_at and last maintenance run. */ |
177 | 4 | image[16] = (val >> 24); |
178 | 4 | image[16+1] = (val >> 16); |
179 | 4 | image[16+2] = (val >> 8); |
180 | 4 | image[16+3] = (val ); |
181 | 4 | image[20] = (val >> 24); |
182 | 4 | image[20+1] = (val >> 16); |
183 | 4 | image[20+2] = (val >> 8); |
184 | 4 | image[20+3] = (val ); |
185 | | |
186 | 4 | if (es_fwrite (image, 32, 1, fp) != 1) |
187 | 0 | return gpg_error_from_syserror (); |
188 | | |
189 | 4 | return 0; |
190 | 4 | } |