1 /* Author: Jason Tang <jtang@tresys.com>
2 * Christopher Ashworth <cashworth@tresys.com>
3 * Ondrej Mosnacek <omosnacek@gmail.com>
4 *
5 * Copyright (C) 2004-2006 Tresys Technology, LLC
6 * Copyright (C) 2005-2021 Red Hat, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdint.h>
26
27 #include <unistd.h>
28 #include <fcntl.h>
29
30 #include <bzlib.h>
31
32 #include "compressed_file.h"
33
34 #include "debug.h"
35
36 #define BZ2_MAGICSTR "BZh"
37 #define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1)
38
39 /* bzip() a data to a file, returning the total number of compressed bytes
40 * in the file. Returns -1 if file could not be compressed. */
bzip(semanage_handle_t * sh,const char * filename,void * data,size_t num_bytes)41 static int bzip(semanage_handle_t *sh, const char *filename, void *data,
42 size_t num_bytes)
43 {
44 BZFILE* b;
45 size_t size = 1<<16;
46 int bzerror;
47 size_t total = 0;
48 size_t len = 0;
49 FILE *f;
50
51 if ((f = fopen(filename, "wb")) == NULL) {
52 return -1;
53 }
54
55 if (!sh->conf->bzip_blocksize) {
56 if (fwrite(data, 1, num_bytes, f) < num_bytes) {
57 fclose(f);
58 return -1;
59 }
60 fclose(f);
61 return 0;
62 }
63
64 b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0);
65 if (bzerror != BZ_OK) {
66 BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
67 fclose(f);
68 return -1;
69 }
70
71 while ( num_bytes > total ) {
72 if (num_bytes - total > size) {
73 len = size;
74 } else {
75 len = num_bytes - total;
76 }
77 BZ2_bzWrite ( &bzerror, b, (uint8_t *)data + total, len );
78 if (bzerror == BZ_IO_ERROR) {
79 BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
80 fclose(f);
81 return -1;
82 }
83 total += len;
84 }
85
86 BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 );
87 fclose(f);
88 if (bzerror == BZ_IO_ERROR) {
89 return -1;
90 }
91 return 0;
92 }
93
94 /* bunzip() a file to '*data', returning the total number of uncompressed bytes
95 * in the file. Returns -1 if file could not be decompressed. */
bunzip(semanage_handle_t * sh,FILE * f,void ** data)96 static ssize_t bunzip(semanage_handle_t *sh, FILE *f, void **data)
97 {
98 BZFILE* b = NULL;
99 size_t nBuf;
100 uint8_t* buf = NULL;
101 size_t size = 1<<18;
102 size_t bufsize = size;
103 int bzerror;
104 size_t total = 0;
105 uint8_t* uncompress = NULL;
106 uint8_t* tmpalloc = NULL;
107 int ret = -1;
108
109 buf = malloc(bufsize);
110 if (buf == NULL) {
111 ERR(sh, "Failure allocating memory.");
112 goto exit;
113 }
114
115 /* Check if the file is bzipped */
116 bzerror = fread(buf, 1, BZ2_MAGICLEN, f);
117 rewind(f);
118 if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) {
119 goto exit;
120 }
121
122 b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 );
123 if ( bzerror != BZ_OK ) {
124 ERR(sh, "Failure opening bz2 archive.");
125 goto exit;
126 }
127
128 uncompress = malloc(size);
129 if (uncompress == NULL) {
130 ERR(sh, "Failure allocating memory.");
131 goto exit;
132 }
133
134 while ( bzerror == BZ_OK) {
135 nBuf = BZ2_bzRead ( &bzerror, b, buf, bufsize);
136 if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) {
137 if (total + nBuf > size) {
138 size *= 2;
139 tmpalloc = realloc(uncompress, size);
140 if (tmpalloc == NULL) {
141 ERR(sh, "Failure allocating memory.");
142 goto exit;
143 }
144 uncompress = tmpalloc;
145 }
146 memcpy(&uncompress[total], buf, nBuf);
147 total += nBuf;
148 }
149 }
150 if ( bzerror != BZ_STREAM_END ) {
151 ERR(sh, "Failure reading bz2 archive.");
152 goto exit;
153 }
154
155 ret = total;
156 *data = uncompress;
157
158 exit:
159 BZ2_bzReadClose ( &bzerror, b );
160 free(buf);
161 if ( ret < 0 ) {
162 free(uncompress);
163 }
164 return ret;
165 }
166
map_compressed_file(semanage_handle_t * sh,const char * path,struct file_contents * contents)167 int map_compressed_file(semanage_handle_t *sh, const char *path,
168 struct file_contents *contents)
169 {
170 ssize_t size = -1;
171 void *uncompress;
172 int ret = 0, fd = -1;
173 FILE *file = NULL;
174
175 fd = open(path, O_RDONLY);
176 if (fd == -1) {
177 ERR(sh, "Unable to open %s\n", path);
178 return -1;
179 }
180
181 file = fdopen(fd, "r");
182 if (file == NULL) {
183 ERR(sh, "Unable to open %s\n", path);
184 close(fd);
185 return -1;
186 }
187
188 if ((size = bunzip(sh, file, &uncompress)) >= 0) {
189 contents->data = uncompress;
190 contents->len = size;
191 contents->compressed = 1;
192 } else {
193 struct stat sb;
194 if (fstat(fd, &sb) == -1 ||
195 (uncompress = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) ==
196 MAP_FAILED) {
197 ret = -1;
198 } else {
199 contents->data = uncompress;
200 contents->len = sb.st_size;
201 contents->compressed = 0;
202 }
203 }
204 fclose(file);
205 return ret;
206 }
207
unmap_compressed_file(struct file_contents * contents)208 void unmap_compressed_file(struct file_contents *contents)
209 {
210 if (!contents->data)
211 return;
212
213 if (contents->compressed) {
214 free(contents->data);
215 } else {
216 munmap(contents->data, contents->len);
217 }
218 }
219
write_compressed_file(semanage_handle_t * sh,const char * path,void * data,size_t len)220 int write_compressed_file(semanage_handle_t *sh, const char *path,
221 void *data, size_t len)
222 {
223 return bzip(sh, path, data, len);
224 }
225