1 | /* |
2 | * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at |
7 | * https://www.openssl.org/source/license.html |
8 | */ |
9 | |
10 | #if defined(__linux) || defined(__sun) || defined(__hpux) |
11 | /* |
12 | * Following definition aliases fopen to fopen64 on above mentioned |
13 | * platforms. This makes it possible to open and sequentially access files |
14 | * larger than 2GB from 32-bit application. It does not allow to traverse |
15 | * them beyond 2GB with fseek/ftell, but on the other hand *no* 32-bit |
16 | * platform permits that, not with fseek/ftell. Not to mention that breaking |
17 | * 2GB limit for seeking would require surgery to *our* API. But sequential |
18 | * access suffices for practical cases when you can run into large files, |
19 | * such as fingerprinting, so we can let API alone. For reference, the list |
20 | * of 32-bit platforms which allow for sequential access of large files |
21 | * without extra "magic" comprise *BSD, Darwin, IRIX... |
22 | */ |
23 | # ifndef _FILE_OFFSET_BITS |
24 | # define _FILE_OFFSET_BITS 64 |
25 | # endif |
26 | #endif |
27 | |
28 | #include <stdio.h> |
29 | #include <errno.h> |
30 | #include "bio_local.h" |
31 | #include <openssl/err.h> |
32 | |
33 | #if !defined(OPENSSL_NO_STDIO) |
34 | |
35 | static int file_write(BIO *h, const char *buf, int num); |
36 | static int file_read(BIO *h, char *buf, int size); |
37 | static int file_puts(BIO *h, const char *str); |
38 | static int file_gets(BIO *h, char *str, int size); |
39 | static long file_ctrl(BIO *h, int cmd, long arg1, void *arg2); |
40 | static int file_new(BIO *h); |
41 | static int file_free(BIO *data); |
42 | static const BIO_METHOD methods_filep = { |
43 | BIO_TYPE_FILE, |
44 | "FILE pointer" , |
45 | /* TODO: Convert to new style write function */ |
46 | bwrite_conv, |
47 | file_write, |
48 | /* TODO: Convert to new style read function */ |
49 | bread_conv, |
50 | file_read, |
51 | file_puts, |
52 | file_gets, |
53 | file_ctrl, |
54 | file_new, |
55 | file_free, |
56 | NULL, /* file_callback_ctrl */ |
57 | }; |
58 | |
59 | BIO *BIO_new_file(const char *filename, const char *mode) |
60 | { |
61 | BIO *ret; |
62 | FILE *file = openssl_fopen(filename, mode); |
63 | int fp_flags = BIO_CLOSE; |
64 | |
65 | if (strchr(mode, 'b') == NULL) |
66 | fp_flags |= BIO_FP_TEXT; |
67 | |
68 | if (file == NULL) { |
69 | ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), |
70 | "calling fopen(%s, %s)" , |
71 | filename, mode); |
72 | if (errno == ENOENT |
73 | #ifdef ENXIO |
74 | || errno == ENXIO |
75 | #endif |
76 | ) |
77 | BIOerr(BIO_F_BIO_NEW_FILE, BIO_R_NO_SUCH_FILE); |
78 | else |
79 | BIOerr(BIO_F_BIO_NEW_FILE, ERR_R_SYS_LIB); |
80 | return NULL; |
81 | } |
82 | if ((ret = BIO_new(BIO_s_file())) == NULL) { |
83 | fclose(file); |
84 | return NULL; |
85 | } |
86 | |
87 | /* we did fopen -> we disengage UPLINK */ |
88 | BIO_clear_flags(ret, BIO_FLAGS_UPLINK_INTERNAL); |
89 | BIO_set_fp(ret, file, fp_flags); |
90 | return ret; |
91 | } |
92 | |
93 | BIO *BIO_new_fp(FILE *stream, int close_flag) |
94 | { |
95 | BIO *ret; |
96 | |
97 | if ((ret = BIO_new(BIO_s_file())) == NULL) |
98 | return NULL; |
99 | |
100 | /* redundant flag, left for documentation purposes */ |
101 | BIO_set_flags(ret, BIO_FLAGS_UPLINK_INTERNAL); |
102 | BIO_set_fp(ret, stream, close_flag); |
103 | return ret; |
104 | } |
105 | |
106 | const BIO_METHOD *BIO_s_file(void) |
107 | { |
108 | return &methods_filep; |
109 | } |
110 | |
111 | static int file_new(BIO *bi) |
112 | { |
113 | bi->init = 0; |
114 | bi->num = 0; |
115 | bi->ptr = NULL; |
116 | bi->flags = BIO_FLAGS_UPLINK_INTERNAL; /* default to UPLINK */ |
117 | return 1; |
118 | } |
119 | |
120 | static int file_free(BIO *a) |
121 | { |
122 | if (a == NULL) |
123 | return 0; |
124 | if (a->shutdown) { |
125 | if ((a->init) && (a->ptr != NULL)) { |
126 | if (a->flags & BIO_FLAGS_UPLINK_INTERNAL) |
127 | UP_fclose(a->ptr); |
128 | else |
129 | fclose(a->ptr); |
130 | a->ptr = NULL; |
131 | a->flags = BIO_FLAGS_UPLINK_INTERNAL; |
132 | } |
133 | a->init = 0; |
134 | } |
135 | return 1; |
136 | } |
137 | |
138 | static int file_read(BIO *b, char *out, int outl) |
139 | { |
140 | int ret = 0; |
141 | |
142 | if (b->init && (out != NULL)) { |
143 | if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) |
144 | ret = UP_fread(out, 1, (int)outl, b->ptr); |
145 | else |
146 | ret = fread(out, 1, (int)outl, (FILE *)b->ptr); |
147 | if (ret == 0 |
148 | && (b->flags & BIO_FLAGS_UPLINK_INTERNAL |
149 | ? UP_ferror((FILE *)b->ptr) : ferror((FILE *)b->ptr))) { |
150 | ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), |
151 | "calling fread()" ); |
152 | BIOerr(BIO_F_FILE_READ, ERR_R_SYS_LIB); |
153 | ret = -1; |
154 | } |
155 | } |
156 | return ret; |
157 | } |
158 | |
159 | static int file_write(BIO *b, const char *in, int inl) |
160 | { |
161 | int ret = 0; |
162 | |
163 | if (b->init && (in != NULL)) { |
164 | if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) |
165 | ret = UP_fwrite(in, (int)inl, 1, b->ptr); |
166 | else |
167 | ret = fwrite(in, (int)inl, 1, (FILE *)b->ptr); |
168 | if (ret) |
169 | ret = inl; |
170 | /* ret=fwrite(in,1,(int)inl,(FILE *)b->ptr); */ |
171 | /* |
172 | * according to Tim Hudson <tjh@openssl.org>, the commented out |
173 | * version above can cause 'inl' write calls under some stupid stdio |
174 | * implementations (VMS) |
175 | */ |
176 | } |
177 | return ret; |
178 | } |
179 | |
180 | static long file_ctrl(BIO *b, int cmd, long num, void *ptr) |
181 | { |
182 | long ret = 1; |
183 | FILE *fp = (FILE *)b->ptr; |
184 | FILE **fpp; |
185 | char p[4]; |
186 | int st; |
187 | |
188 | switch (cmd) { |
189 | case BIO_C_FILE_SEEK: |
190 | case BIO_CTRL_RESET: |
191 | if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) |
192 | ret = (long)UP_fseek(b->ptr, num, 0); |
193 | else |
194 | ret = (long)fseek(fp, num, 0); |
195 | break; |
196 | case BIO_CTRL_EOF: |
197 | if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) |
198 | ret = (long)UP_feof(fp); |
199 | else |
200 | ret = (long)feof(fp); |
201 | break; |
202 | case BIO_C_FILE_TELL: |
203 | case BIO_CTRL_INFO: |
204 | if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) |
205 | ret = UP_ftell(b->ptr); |
206 | else |
207 | ret = ftell(fp); |
208 | break; |
209 | case BIO_C_SET_FILE_PTR: |
210 | file_free(b); |
211 | b->shutdown = (int)num & BIO_CLOSE; |
212 | b->ptr = ptr; |
213 | b->init = 1; |
214 | # if BIO_FLAGS_UPLINK_INTERNAL!=0 |
215 | # if defined(__MINGW32__) && defined(__MSVCRT__) && !defined(_IOB_ENTRIES) |
216 | # define _IOB_ENTRIES 20 |
217 | # endif |
218 | /* Safety net to catch purely internal BIO_set_fp calls */ |
219 | # if defined(_MSC_VER) && _MSC_VER>=1900 |
220 | if (ptr == stdin || ptr == stdout || ptr == stderr) |
221 | BIO_clear_flags(b, BIO_FLAGS_UPLINK_INTERNAL); |
222 | # elif defined(_IOB_ENTRIES) |
223 | if ((size_t)ptr >= (size_t)stdin && |
224 | (size_t)ptr < (size_t)(stdin + _IOB_ENTRIES)) |
225 | BIO_clear_flags(b, BIO_FLAGS_UPLINK_INTERNAL); |
226 | # endif |
227 | # endif |
228 | # ifdef UP_fsetmod |
229 | if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) |
230 | UP_fsetmod(b->ptr, (char)((num & BIO_FP_TEXT) ? 't' : 'b')); |
231 | else |
232 | # endif |
233 | { |
234 | # if defined(OPENSSL_SYS_WINDOWS) |
235 | int fd = _fileno((FILE *)ptr); |
236 | if (num & BIO_FP_TEXT) |
237 | _setmode(fd, _O_TEXT); |
238 | else |
239 | _setmode(fd, _O_BINARY); |
240 | # elif defined(OPENSSL_SYS_MSDOS) |
241 | int fd = fileno((FILE *)ptr); |
242 | /* Set correct text/binary mode */ |
243 | if (num & BIO_FP_TEXT) |
244 | _setmode(fd, _O_TEXT); |
245 | /* Dangerous to set stdin/stdout to raw (unless redirected) */ |
246 | else { |
247 | if (fd == STDIN_FILENO || fd == STDOUT_FILENO) { |
248 | if (isatty(fd) <= 0) |
249 | _setmode(fd, _O_BINARY); |
250 | } else |
251 | _setmode(fd, _O_BINARY); |
252 | } |
253 | # elif defined(OPENSSL_SYS_WIN32_CYGWIN) |
254 | int fd = fileno((FILE *)ptr); |
255 | if (!(num & BIO_FP_TEXT)) |
256 | setmode(fd, O_BINARY); |
257 | # endif |
258 | } |
259 | break; |
260 | case BIO_C_SET_FILENAME: |
261 | file_free(b); |
262 | b->shutdown = (int)num & BIO_CLOSE; |
263 | if (num & BIO_FP_APPEND) { |
264 | if (num & BIO_FP_READ) |
265 | OPENSSL_strlcpy(p, "a+" , sizeof(p)); |
266 | else |
267 | OPENSSL_strlcpy(p, "a" , sizeof(p)); |
268 | } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) |
269 | OPENSSL_strlcpy(p, "r+" , sizeof(p)); |
270 | else if (num & BIO_FP_WRITE) |
271 | OPENSSL_strlcpy(p, "w" , sizeof(p)); |
272 | else if (num & BIO_FP_READ) |
273 | OPENSSL_strlcpy(p, "r" , sizeof(p)); |
274 | else { |
275 | BIOerr(BIO_F_FILE_CTRL, BIO_R_BAD_FOPEN_MODE); |
276 | ret = 0; |
277 | break; |
278 | } |
279 | # if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) |
280 | if (!(num & BIO_FP_TEXT)) |
281 | OPENSSL_strlcat(p, "b" , sizeof(p)); |
282 | else |
283 | OPENSSL_strlcat(p, "t" , sizeof(p)); |
284 | # elif defined(OPENSSL_SYS_WIN32_CYGWIN) |
285 | if (!(num & BIO_FP_TEXT)) |
286 | OPENSSL_strlcat(p, "b" , sizeof(p)); |
287 | # endif |
288 | fp = openssl_fopen(ptr, p); |
289 | if (fp == NULL) { |
290 | ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), |
291 | "calling fopen(%s, %s)" , |
292 | ptr, p); |
293 | BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); |
294 | ret = 0; |
295 | break; |
296 | } |
297 | b->ptr = fp; |
298 | b->init = 1; |
299 | /* we did fopen -> we disengage UPLINK */ |
300 | BIO_clear_flags(b, BIO_FLAGS_UPLINK_INTERNAL); |
301 | break; |
302 | case BIO_C_GET_FILE_PTR: |
303 | /* the ptr parameter is actually a FILE ** in this case. */ |
304 | if (ptr != NULL) { |
305 | fpp = (FILE **)ptr; |
306 | *fpp = (FILE *)b->ptr; |
307 | } |
308 | break; |
309 | case BIO_CTRL_GET_CLOSE: |
310 | ret = (long)b->shutdown; |
311 | break; |
312 | case BIO_CTRL_SET_CLOSE: |
313 | b->shutdown = (int)num; |
314 | break; |
315 | case BIO_CTRL_FLUSH: |
316 | st = b->flags & BIO_FLAGS_UPLINK_INTERNAL |
317 | ? UP_fflush(b->ptr) : fflush((FILE *)b->ptr); |
318 | if (st == EOF) { |
319 | ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), |
320 | "calling fflush()" ); |
321 | BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); |
322 | ret = 0; |
323 | } |
324 | break; |
325 | case BIO_CTRL_DUP: |
326 | ret = 1; |
327 | break; |
328 | |
329 | case BIO_CTRL_WPENDING: |
330 | case BIO_CTRL_PENDING: |
331 | case BIO_CTRL_PUSH: |
332 | case BIO_CTRL_POP: |
333 | default: |
334 | ret = 0; |
335 | break; |
336 | } |
337 | return ret; |
338 | } |
339 | |
340 | static int file_gets(BIO *bp, char *buf, int size) |
341 | { |
342 | int ret = 0; |
343 | |
344 | buf[0] = '\0'; |
345 | if (bp->flags & BIO_FLAGS_UPLINK_INTERNAL) { |
346 | if (!UP_fgets(buf, size, bp->ptr)) |
347 | goto err; |
348 | } else { |
349 | if (!fgets(buf, size, (FILE *)bp->ptr)) |
350 | goto err; |
351 | } |
352 | if (buf[0] != '\0') |
353 | ret = strlen(buf); |
354 | err: |
355 | return ret; |
356 | } |
357 | |
358 | static int file_puts(BIO *bp, const char *str) |
359 | { |
360 | int n, ret; |
361 | |
362 | n = strlen(str); |
363 | ret = file_write(bp, str, n); |
364 | return ret; |
365 | } |
366 | |
367 | #else |
368 | |
369 | static int file_write(BIO *b, const char *in, int inl) |
370 | { |
371 | return -1; |
372 | } |
373 | static int file_read(BIO *b, char *out, int outl) |
374 | { |
375 | return -1; |
376 | } |
377 | static int file_puts(BIO *bp, const char *str) |
378 | { |
379 | return -1; |
380 | } |
381 | static int file_gets(BIO *bp, char *buf, int size) |
382 | { |
383 | return 0; |
384 | } |
385 | static long file_ctrl(BIO *b, int cmd, long num, void *ptr) |
386 | { |
387 | return 0; |
388 | } |
389 | static int file_new(BIO *bi) |
390 | { |
391 | return 0; |
392 | } |
393 | static int file_free(BIO *a) |
394 | { |
395 | return 0; |
396 | } |
397 | |
398 | static const BIO_METHOD methods_filep = { |
399 | BIO_TYPE_FILE, |
400 | "FILE pointer" , |
401 | /* TODO: Convert to new style write function */ |
402 | bwrite_conv, |
403 | file_write, |
404 | /* TODO: Convert to new style read function */ |
405 | bread_conv, |
406 | file_read, |
407 | file_puts, |
408 | file_gets, |
409 | file_ctrl, |
410 | file_new, |
411 | file_free, |
412 | NULL, /* file_callback_ctrl */ |
413 | }; |
414 | |
415 | const BIO_METHOD *BIO_s_file(void) |
416 | { |
417 | return &methods_filep; |
418 | } |
419 | |
420 | BIO *BIO_new_file(const char *filename, const char *mode) |
421 | { |
422 | return NULL; |
423 | } |
424 | |
425 | #endif /* OPENSSL_NO_STDIO */ |
426 | |