1 /* 2 * Copyright 1995-2021 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 bwrite_conv, 46 file_write, 47 bread_conv, 48 file_read, 49 file_puts, 50 file_gets, 51 file_ctrl, 52 file_new, 53 file_free, 54 NULL, /* file_callback_ctrl */ 55 }; 56 57 BIO *BIO_new_file(const char *filename, const char *mode) 58 { 59 BIO *ret; 60 FILE *file = openssl_fopen(filename, mode); 61 int fp_flags = BIO_CLOSE; 62 63 if (strchr(mode, 'b') == NULL) 64 fp_flags |= BIO_FP_TEXT; 65 66 if (file == NULL) { 67 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 68 "calling fopen(%s, %s)", 69 filename, mode); 70 if (errno == ENOENT 71 #ifdef ENXIO 72 || errno == ENXIO 73 #endif 74 ) 75 ERR_raise(ERR_LIB_BIO, BIO_R_NO_SUCH_FILE); 76 else 77 ERR_raise(ERR_LIB_BIO, ERR_R_SYS_LIB); 78 return NULL; 79 } 80 if ((ret = BIO_new(BIO_s_file())) == NULL) { 81 fclose(file); 82 return NULL; 83 } 84 85 /* we did fopen -> we disengage UPLINK */ 86 BIO_clear_flags(ret, BIO_FLAGS_UPLINK_INTERNAL); 87 BIO_set_fp(ret, file, fp_flags); 88 return ret; 89 } 90 91 BIO *BIO_new_fp(FILE *stream, int close_flag) 92 { 93 BIO *ret; 94 95 if ((ret = BIO_new(BIO_s_file())) == NULL) 96 return NULL; 97 98 /* redundant flag, left for documentation purposes */ 99 BIO_set_flags(ret, BIO_FLAGS_UPLINK_INTERNAL); 100 BIO_set_fp(ret, stream, close_flag); 101 return ret; 102 } 103 104 const BIO_METHOD *BIO_s_file(void) 105 { 106 return &methods_filep; 107 } 108 109 static int file_new(BIO *bi) 110 { 111 bi->init = 0; 112 bi->num = 0; 113 bi->ptr = NULL; 114 bi->flags = BIO_FLAGS_UPLINK_INTERNAL; /* default to UPLINK */ 115 return 1; 116 } 117 118 static int file_free(BIO *a) 119 { 120 if (a == NULL) 121 return 0; 122 if (a->shutdown) { 123 if ((a->init) && (a->ptr != NULL)) { 124 if (a->flags & BIO_FLAGS_UPLINK_INTERNAL) 125 UP_fclose(a->ptr); 126 else 127 fclose(a->ptr); 128 a->ptr = NULL; 129 a->flags = BIO_FLAGS_UPLINK_INTERNAL; 130 } 131 a->init = 0; 132 } 133 return 1; 134 } 135 136 static int file_read(BIO *b, char *out, int outl) 137 { 138 int ret = 0; 139 140 if (b->init && (out != NULL)) { 141 if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) 142 ret = UP_fread(out, 1, (int)outl, b->ptr); 143 else 144 ret = fread(out, 1, (int)outl, (FILE *)b->ptr); 145 if (ret == 0 146 && (b->flags & BIO_FLAGS_UPLINK_INTERNAL 147 ? UP_ferror((FILE *)b->ptr) : ferror((FILE *)b->ptr))) { 148 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 149 "calling fread()"); 150 ERR_raise(ERR_LIB_BIO, ERR_R_SYS_LIB); 151 ret = -1; 152 } 153 } 154 return ret; 155 } 156 157 static int file_write(BIO *b, const char *in, int inl) 158 { 159 int ret = 0; 160 161 if (b->init && (in != NULL)) { 162 if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) 163 ret = UP_fwrite(in, (int)inl, 1, b->ptr); 164 else 165 ret = fwrite(in, (int)inl, 1, (FILE *)b->ptr); 166 if (ret) 167 ret = inl; 168 /* ret=fwrite(in,1,(int)inl,(FILE *)b->ptr); */ 169 /* 170 * according to Tim Hudson <tjh@openssl.org>, the commented out 171 * version above can cause 'inl' write calls under some stupid stdio 172 * implementations (VMS) 173 */ 174 } 175 return ret; 176 } 177 178 static long file_ctrl(BIO *b, int cmd, long num, void *ptr) 179 { 180 long ret = 1; 181 FILE *fp = (FILE *)b->ptr; 182 FILE **fpp; 183 char p[4]; 184 int st; 185 186 switch (cmd) { 187 case BIO_C_FILE_SEEK: 188 case BIO_CTRL_RESET: 189 if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) 190 ret = (long)UP_fseek(b->ptr, num, 0); 191 else 192 ret = (long)fseek(fp, num, 0); 193 break; 194 case BIO_CTRL_EOF: 195 if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) 196 ret = (long)UP_feof(fp); 197 else 198 ret = (long)feof(fp); 199 break; 200 case BIO_C_FILE_TELL: 201 case BIO_CTRL_INFO: 202 if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) 203 ret = UP_ftell(b->ptr); 204 else 205 ret = ftell(fp); 206 break; 207 case BIO_C_SET_FILE_PTR: 208 file_free(b); 209 b->shutdown = (int)num & BIO_CLOSE; 210 b->ptr = ptr; 211 b->init = 1; 212 # if BIO_FLAGS_UPLINK_INTERNAL!=0 213 # if defined(__MINGW32__) && defined(__MSVCRT__) && !defined(_IOB_ENTRIES) 214 # define _IOB_ENTRIES 20 215 # endif 216 /* Safety net to catch purely internal BIO_set_fp calls */ 217 # if (defined(_MSC_VER) && _MSC_VER>=1900) || defined(__BORLANDC__) 218 if (ptr == stdin || ptr == stdout || ptr == stderr) 219 BIO_clear_flags(b, BIO_FLAGS_UPLINK_INTERNAL); 220 # elif defined(_IOB_ENTRIES) 221 if ((size_t)ptr >= (size_t)stdin && 222 (size_t)ptr < (size_t)(stdin + _IOB_ENTRIES)) 223 BIO_clear_flags(b, BIO_FLAGS_UPLINK_INTERNAL); 224 # endif 225 # endif 226 # ifdef UP_fsetmod 227 if (b->flags & BIO_FLAGS_UPLINK_INTERNAL) 228 UP_fsetmod(b->ptr, (char)((num & BIO_FP_TEXT) ? 't' : 'b')); 229 else 230 # endif 231 { 232 # if defined(OPENSSL_SYS_WINDOWS) 233 int fd = _fileno((FILE *)ptr); 234 if (num & BIO_FP_TEXT) 235 _setmode(fd, _O_TEXT); 236 else 237 _setmode(fd, _O_BINARY); 238 /* 239 * Reports show that ftell() isn't trustable in text mode. 240 * This has been confirmed as a bug in the Universal C RTL, see 241 * https://developercommunity.visualstudio.com/content/problem/425878/fseek-ftell-fail-in-text-mode-for-unix-style-text.html 242 * The suggested work-around from Microsoft engineering is to 243 * turn off buffering until the bug is resolved. 244 */ 245 if ((num & BIO_FP_TEXT) != 0) 246 setvbuf((FILE *)ptr, NULL, _IONBF, 0); 247 # elif defined(OPENSSL_SYS_MSDOS) 248 int fd = fileno((FILE *)ptr); 249 /* Set correct text/binary mode */ 250 if (num & BIO_FP_TEXT) 251 _setmode(fd, _O_TEXT); 252 /* Dangerous to set stdin/stdout to raw (unless redirected) */ 253 else { 254 if (fd == STDIN_FILENO || fd == STDOUT_FILENO) { 255 if (isatty(fd) <= 0) 256 _setmode(fd, _O_BINARY); 257 } else 258 _setmode(fd, _O_BINARY); 259 } 260 # elif defined(OPENSSL_SYS_WIN32_CYGWIN) 261 int fd = fileno((FILE *)ptr); 262 if (!(num & BIO_FP_TEXT)) 263 setmode(fd, O_BINARY); 264 # endif 265 } 266 break; 267 case BIO_C_SET_FILENAME: 268 file_free(b); 269 b->shutdown = (int)num & BIO_CLOSE; 270 if (num & BIO_FP_APPEND) { 271 if (num & BIO_FP_READ) 272 OPENSSL_strlcpy(p, "a+", sizeof(p)); 273 else 274 OPENSSL_strlcpy(p, "a", sizeof(p)); 275 } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) 276 OPENSSL_strlcpy(p, "r+", sizeof(p)); 277 else if (num & BIO_FP_WRITE) 278 OPENSSL_strlcpy(p, "w", sizeof(p)); 279 else if (num & BIO_FP_READ) 280 OPENSSL_strlcpy(p, "r", sizeof(p)); 281 else { 282 ERR_raise(ERR_LIB_BIO, BIO_R_BAD_FOPEN_MODE); 283 ret = 0; 284 break; 285 } 286 # if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) 287 if (!(num & BIO_FP_TEXT)) 288 OPENSSL_strlcat(p, "b", sizeof(p)); 289 else 290 OPENSSL_strlcat(p, "t", sizeof(p)); 291 # elif defined(OPENSSL_SYS_WIN32_CYGWIN) 292 if (!(num & BIO_FP_TEXT)) 293 OPENSSL_strlcat(p, "b", sizeof(p)); 294 # endif 295 fp = openssl_fopen(ptr, p); 296 if (fp == NULL) { 297 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 298 "calling fopen(%s, %s)", 299 ptr, p); 300 ERR_raise(ERR_LIB_BIO, ERR_R_SYS_LIB); 301 ret = 0; 302 break; 303 } 304 b->ptr = fp; 305 b->init = 1; 306 /* we did fopen -> we disengage UPLINK */ 307 BIO_clear_flags(b, BIO_FLAGS_UPLINK_INTERNAL); 308 break; 309 case BIO_C_GET_FILE_PTR: 310 /* the ptr parameter is actually a FILE ** in this case. */ 311 if (ptr != NULL) { 312 fpp = (FILE **)ptr; 313 *fpp = (FILE *)b->ptr; 314 } 315 break; 316 case BIO_CTRL_GET_CLOSE: 317 ret = (long)b->shutdown; 318 break; 319 case BIO_CTRL_SET_CLOSE: 320 b->shutdown = (int)num; 321 break; 322 case BIO_CTRL_FLUSH: 323 st = b->flags & BIO_FLAGS_UPLINK_INTERNAL 324 ? UP_fflush(b->ptr) : fflush((FILE *)b->ptr); 325 if (st == EOF) { 326 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 327 "calling fflush()"); 328 ERR_raise(ERR_LIB_BIO, ERR_R_SYS_LIB); 329 ret = 0; 330 } 331 break; 332 case BIO_CTRL_DUP: 333 ret = 1; 334 break; 335 336 case BIO_CTRL_WPENDING: 337 case BIO_CTRL_PENDING: 338 case BIO_CTRL_PUSH: 339 case BIO_CTRL_POP: 340 default: 341 ret = 0; 342 break; 343 } 344 return ret; 345 } 346 347 static int file_gets(BIO *bp, char *buf, int size) 348 { 349 int ret = 0; 350 351 buf[0] = '\0'; 352 if (bp->flags & BIO_FLAGS_UPLINK_INTERNAL) { 353 if (!UP_fgets(buf, size, bp->ptr)) 354 goto err; 355 } else { 356 if (!fgets(buf, size, (FILE *)bp->ptr)) 357 goto err; 358 } 359 if (buf[0] != '\0') 360 ret = strlen(buf); 361 err: 362 return ret; 363 } 364 365 static int file_puts(BIO *bp, const char *str) 366 { 367 int n, ret; 368 369 n = strlen(str); 370 ret = file_write(bp, str, n); 371 return ret; 372 } 373 374 #else 375 376 static int file_write(BIO *b, const char *in, int inl) 377 { 378 return -1; 379 } 380 static int file_read(BIO *b, char *out, int outl) 381 { 382 return -1; 383 } 384 static int file_puts(BIO *bp, const char *str) 385 { 386 return -1; 387 } 388 static int file_gets(BIO *bp, char *buf, int size) 389 { 390 return 0; 391 } 392 static long file_ctrl(BIO *b, int cmd, long num, void *ptr) 393 { 394 return 0; 395 } 396 static int file_new(BIO *bi) 397 { 398 return 0; 399 } 400 static int file_free(BIO *a) 401 { 402 return 0; 403 } 404 405 static const BIO_METHOD methods_filep = { 406 BIO_TYPE_FILE, 407 "FILE pointer", 408 bwrite_conv, 409 file_write, 410 bread_conv, 411 file_read, 412 file_puts, 413 file_gets, 414 file_ctrl, 415 file_new, 416 file_free, 417 NULL, /* file_callback_ctrl */ 418 }; 419 420 const BIO_METHOD *BIO_s_file(void) 421 { 422 return &methods_filep; 423 } 424 425 BIO *BIO_new_file(const char *filename, const char *mode) 426 { 427 return NULL; 428 } 429 430 #endif /* OPENSSL_NO_STDIO */ 431