394bba39aadf4ec429190d1e7fd3f6376e3c06f2
[dragonfly.git] / usr.sbin / pkg_install / sign / gzip.c
1 /* $OpenBSD: gzip.c,v 1.3 1999/10/04 21:46:28 espie Exp $ */
2 /*-
3  * Copyright (c) 1999 Marc Espie.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Marc Espie for the OpenBSD
16  * Project.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
21  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
22  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * $FreeBSD: src/usr.sbin/pkg_install/sign/gzip.c,v 1.1.2.3 2002/08/20 06:35:08 obrien Exp $
31  * $DragonFly: src/usr.sbin/pkg_install/sign/Attic/gzip.c,v 1.2 2003/06/17 04:29:59 dillon Exp $
32  */
33
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <assert.h>
39 #include <string.h>
40 #include "stand.h"
41 #include "gzip.h"
42 #include "pgp.h"
43
44 /*
45  * Signatures follow a simple format
46  * (endianess was chosen to conform to gzip header format)
47  */
48
49 SIGNTAG known_tags[KNOWN_TAGS] = { 
50         {'S', 'I', 'G', 'P', 'G', 'P', 0, 0 },
51         {'C', 'K', 'S', 'H', 'A', '1', 0, 0 },
52         {'C', 'R', 'X', '5', '0', '9', 0, 0 },
53         {'S', 'i', 'g', 'P', 'G', 'P', 0, 0 }   /* old format */
54 };
55
56 void
57 sign_fill_tag(sign)
58         struct signature *sign;
59 {
60         sign->tag[6] = sign->length % 256;
61         sign->tag[7] = sign->length / 256;
62 }
63         
64 void
65 sign_fill_length(sign)
66         struct signature *sign;
67 {
68         sign->length = sign->tag[6] + 256 * sign->tag[7];
69 }
70
71 static size_t
72 stack_sign(match, t, f, sign)
73         SIGNTAG match;
74         int t;
75         FILE *f;
76         struct signature **sign;
77 {
78         struct signature *new_sign;
79         size_t length;
80         
81         new_sign = malloc(sizeof *new_sign);
82         if (new_sign == NULL)
83                 return 0;
84         new_sign->type = t;
85         new_sign->next = NULL;
86         memcpy(new_sign->tag, match, sizeof(SIGNTAG));  
87         sign_fill_length(new_sign);
88         new_sign->data = malloc(new_sign->length);
89         if (new_sign->data == NULL || 
90                 fread(new_sign->data, 1, new_sign->length, f) != new_sign->length) {
91                 free_signature(new_sign);
92                 return 0;
93         }
94         length = new_sign->length;
95         if (sign != NULL) {
96                 if (!*sign)
97                         *sign = new_sign;
98                 else {
99                         while ((*sign)->next != NULL)
100                                 sign = &((*sign)->next);
101                         (*sign)->next = new_sign;
102                 }
103         } else 
104                 free_signature(new_sign);
105         return length;
106 }
107
108
109 static int 
110 add_sign(f, sign)
111         FILE *f;
112         struct signature **sign;
113 {
114         SIGNTAG match;
115         int i;
116
117         if (fread(match, 1, sizeof(SIGNTAG), f) != sizeof(SIGNTAG)) 
118                 return -1;
119         for (i = 0; i < KNOWN_TAGS; i++) {
120                 if (memcmp(match, known_tags[i], TAGCHECK) == 0) {
121                         unsigned int sign_length = stack_sign(match, i, f, sign);
122                         if (sign_length > 0)
123                                 return sign_length + sizeof(SIGNTAG);
124                         else
125                                 return -1;
126                 }
127         }
128         return 0;
129 }
130
131 static int
132 gzip_magic(f)
133         FILE *f;
134 {
135         int c, d;
136
137         c = fgetc(f);
138         d = fgetc(f);
139         if ((unsigned char)c != (unsigned char)GZIP_MAGIC0 
140                  || (unsigned char)d != (unsigned char)GZIP_MAGIC1)     
141                 return 0;
142         else
143                 return 1;
144 }
145
146 static int
147 fill_gzip_fields(f, h)
148         FILE *f;
149         struct mygzip_header *h;
150 {
151         int method, flags;
152                 
153         method = fgetc(f);
154         flags = fgetc(f);
155
156         if (method == EOF || flags == EOF || fread(h->stamp, 1, 6, f) != 6)
157                 return 0;
158         h->method = (char)method;
159         h->flags = (char)flags;
160         if ((h->flags & CONTINUATION) != 0)
161                 if (fread(h->part, 1, 2, f) != 2)
162                         return 0;
163         return 1;
164 }
165
166 /* retrieve a gzip header, including signatures */
167 int 
168 gzip_read_header(f, h, sign)
169         FILE *f;
170         struct mygzip_header *h;
171         struct signature **sign;
172 {
173         if (sign != NULL)
174                 *sign = NULL;
175         if (!gzip_magic(f) || !fill_gzip_fields(f, h))
176                 return GZIP_NOT_GZIP;
177
178         if ((h->flags & EXTRA_FIELD) == 0) {
179                 h->remaining = 0;
180                 return GZIP_UNSIGNED;
181         }
182         else {
183                 int c;
184
185                 c = fgetc(f);
186                 if (c == EOF)
187                         return GZIP_NOT_GZIP;
188                 h->remaining = (unsigned)c;
189                 c = fgetc(f);
190                 if (c == EOF)
191                         return GZIP_NOT_PGPSIGNED;
192                 h->remaining += ((unsigned) c) << 8;
193                 while (h->remaining >= sizeof(SIGNTAG)) {
194                         int sign_length = add_sign(f, sign);
195                         if (sign_length > 0)
196                                 h->remaining -= sign_length;
197                         if (sign_length < 0)
198                                 return GZIP_NOT_GZIP;
199                         if (sign_length == 0)
200                                 return GZIP_SIGNED;
201                 }
202         return GZIP_SIGNED;
203         }
204 }
205
206 static unsigned 
207 sign_length(sign)
208         struct signature *sign;
209 {
210         unsigned total = 0;
211
212         while (sign != NULL)    {
213                 total += sizeof(SIGNTAG) + sign->length;
214                 sign = sign->next;
215         }
216         return total;
217 }
218
219 struct mydata {
220         FILE *file;
221         int ok;
222 };
223
224 static void myadd(arg, buffer, size)
225         void *arg;
226         const char *buffer;
227         size_t size;
228 {
229         struct mydata *d = arg;
230
231         if (fwrite(buffer, 1, size, d->file) == size)
232                 d->ok = 1;
233         else
234                 d->ok = 0;
235 }
236
237 /* write a gzip header, including signatures */
238 int 
239 gzip_write_header(f, h, sign)
240         FILE *f;
241         const struct mygzip_header *h;
242         struct signature *sign;
243 {
244         struct mydata d;
245         d.file = f;
246         if (gzip_copy_header(h, sign, myadd, &d) == 0)
247                 return 0;
248         return d.ok;
249 }
250                 
251 int 
252 gzip_copy_header(h, sign, add, data)
253         const struct mygzip_header *h;
254         struct signature *sign;
255         void (*add)(void *, const char *, size_t);
256         void *data;
257 {
258         char flags;
259         size_t length;
260         size_t buflength;
261         size_t i;
262         char *buffer;
263
264         length = h->remaining + sign_length(sign);
265         if (length) {
266                 buflength = length + 2;
267                 flags = h->flags | EXTRA_FIELD;
268         } else {
269                 flags = h->flags & ~EXTRA_FIELD;
270                 buflength = 0;
271         }
272         buflength += 10;
273         if ((h->flags & CONTINUATION) != 0)
274                 buflength += 2;
275
276         buffer = malloc(buflength);
277         if (buffer == NULL)
278                 return 0;
279
280         i = 0;
281         buffer[i++] = GZIP_MAGIC0;
282         buffer[i++] = GZIP_MAGIC1;
283         buffer[i++] = h->method;
284         buffer[i++] = flags;
285         memcpy(buffer+i, h->stamp, 6);
286         i += 6;
287         if ((flags & CONTINUATION) != 0) {
288                 memcpy(buffer+i, h->part, 2);
289                 i += 2;
290         }
291         if (length) {
292                 buffer[i++] = (char)(length % 256);
293                 buffer[i++] = (char)(length / 256);
294                 while (sign != NULL) {
295                         memcpy(buffer+i, sign->tag, sizeof(SIGNTAG));
296                         i += sizeof(SIGNTAG);
297                         memcpy(buffer+i, sign->data, sign->length);
298                         i += sign->length;
299                         sign = sign->next;
300                 }
301         }
302         (*add)(data, buffer, buflength);
303         free(buffer);
304         return 1;
305 }
306         
307 void 
308 free_signature(sign)
309         struct signature *sign;
310 {
311         struct signature *next;
312
313         while (sign != NULL) {
314                 next = sign->next;
315                 free(sign->data);
316                 free(sign);
317                 sign = next;
318         }
319 }