X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fbio%2Fbss_file.c;h=081c7f16322f8332c5a74f033cee55ab652eba67;hp=e3af936374020385a2e50d991352feeb33ff1fcb;hb=800b299b0a53c871be57c4b2c97c95d6642489ea;hpb=0fc5cf0870c0c9e4240e118ee7a86e5d8b4a6891 diff --git a/crypto/bio/bss_file.c b/crypto/bio/bss_file.c index e3af936374..081c7f1632 100644 --- a/crypto/bio/bss_file.c +++ b/crypto/bio/bss_file.c @@ -1,25 +1,24 @@ -/* crypto/bio/bss_file.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. - * + * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * + * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,10 +33,10 @@ * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from + * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * + * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -49,270 +48,463 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ -/* - * 03-Dec-1997 rdenny@dc3.com Fix bug preventing use of stdin/stdout - * with binary data (e.g. asn1parse -inform DER < xxx) under - * Windows +/*- + * 03-Dec-1997 rdenny@dc3.com Fix bug preventing use of stdin/stdout + * with binary data (e.g. asn1parse -inform DER < xxx) under + * Windows */ #ifndef HEADER_BSS_FILE_C -#define HEADER_BSS_FILE_C - -#include -#include -#include "cryptlib.h" -#include -#include - -#if !defined(OPENSSL_NO_STDIO) - -static int MS_CALLBACK file_write(BIO *h, const char *buf, int num); -static int MS_CALLBACK file_read(BIO *h, char *buf, int size); -static int MS_CALLBACK file_puts(BIO *h, const char *str); -static int MS_CALLBACK file_gets(BIO *h, char *str, int size); -static long MS_CALLBACK file_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int MS_CALLBACK file_new(BIO *h); -static int MS_CALLBACK file_free(BIO *data); -static BIO_METHOD methods_filep= - { - BIO_TYPE_FILE, - "FILE pointer", - file_write, - file_read, - file_puts, - file_gets, - file_ctrl, - file_new, - file_free, - NULL, - }; +# define HEADER_BSS_FILE_C + +# if defined(__linux) || defined(__sun) || defined(__hpux) +/* + * Following definition aliases fopen to fopen64 on above mentioned + * platforms. This makes it possible to open and sequentially access files + * larger than 2GB from 32-bit application. It does not allow to traverse + * them beyond 2GB with fseek/ftell, but on the other hand *no* 32-bit + * platform permits that, not with fseek/ftell. Not to mention that breaking + * 2GB limit for seeking would require surgery to *our* API. But sequential + * access suffices for practical cases when you can run into large files, + * such as fingerprinting, so we can let API alone. For reference, the list + * of 32-bit platforms which allow for sequential access of large files + * without extra "magic" comprise *BSD, Darwin, IRIX... + */ +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# endif + +# include +# include +# include "bio_lcl.h" +# include + +# if !defined(OPENSSL_NO_STDIO) + +static int file_write(BIO *h, const char *buf, int num); +static int file_read(BIO *h, char *buf, int size); +static int file_puts(BIO *h, const char *str); +static int file_gets(BIO *h, char *str, int size); +static long file_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int file_new(BIO *h); +static int file_free(BIO *data); +static const BIO_METHOD methods_filep = { + BIO_TYPE_FILE, + "FILE pointer", + file_write, + file_read, + file_puts, + file_gets, + file_ctrl, + file_new, + file_free, + NULL, +}; + +static FILE *file_fopen(const char *filename, const char *mode) +{ + FILE *file = NULL; + +# if defined(_WIN32) && defined(CP_UTF8) + int sz, len_0 = (int)strlen(filename) + 1; + DWORD flags; + + /* + * Basically there are three cases to cover: a) filename is + * pure ASCII string; b) actual UTF-8 encoded string and + * c) locale-ized string, i.e. one containing 8-bit + * characters that are meaningful in current system locale. + * If filename is pure ASCII or real UTF-8 encoded string, + * MultiByteToWideChar succeeds and _wfopen works. If + * filename is locale-ized string, chances are that + * MultiByteToWideChar fails reporting + * ERROR_NO_UNICODE_TRANSLATION, in which case we fall + * back to fopen... + */ + if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS), + filename, len_0, NULL, 0)) > 0 || + (GetLastError() == ERROR_INVALID_FLAGS && + (sz = MultiByteToWideChar(CP_UTF8, (flags = 0), + filename, len_0, NULL, 0)) > 0) + ) { + WCHAR wmode[8]; + WCHAR *wfilename = _alloca(sz * sizeof(WCHAR)); + + if (MultiByteToWideChar(CP_UTF8, flags, + filename, len_0, wfilename, sz) && + MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1, + wmode, OSSL_NELEM(wmode)) && + (file = _wfopen(wfilename, wmode)) == NULL && + (errno == ENOENT || errno == EBADF) + ) { + /* + * UTF-8 decode succeeded, but no file, filename + * could still have been locale-ized... + */ + file = fopen(filename, mode); + } + } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { + file = fopen(filename, mode); + } +# else + file = fopen(filename, mode); +# endif + return (file); +} BIO *BIO_new_file(const char *filename, const char *mode) - { - BIO *ret; - FILE *file; - - if ((file=fopen(filename,mode)) == NULL) - { - SYSerr(SYS_F_FOPEN,get_last_sys_error()); - ERR_add_error_data(5,"fopen('",filename,"','",mode,"')"); - if(errno == ENOENT) - BIOerr(BIO_F_BIO_NEW_FILE,BIO_R_NO_SUCH_FILE); - else - BIOerr(BIO_F_BIO_NEW_FILE,ERR_R_SYS_LIB); - return(NULL); - } - if ((ret=BIO_new(BIO_s_file_internal())) == NULL) - return(NULL); - - BIO_set_fp(ret,file,BIO_CLOSE); - return(ret); - } +{ + BIO *ret; + FILE *file = file_fopen(filename, mode); + + if (file == NULL) { + SYSerr(SYS_F_FOPEN, get_last_sys_error()); + ERR_add_error_data(5, "fopen('", filename, "','", mode, "')"); + if (errno == ENOENT) + BIOerr(BIO_F_BIO_NEW_FILE, BIO_R_NO_SUCH_FILE); + else + BIOerr(BIO_F_BIO_NEW_FILE, ERR_R_SYS_LIB); + return (NULL); + } + if ((ret = BIO_new(BIO_s_file())) == NULL) { + fclose(file); + return (NULL); + } + + BIO_clear_flags(ret, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage + * UPLINK */ + BIO_set_fp(ret, file, BIO_CLOSE); + return (ret); +} BIO *BIO_new_fp(FILE *stream, int close_flag) - { - BIO *ret; - - if ((ret=BIO_new(BIO_s_file())) == NULL) - return(NULL); - - BIO_set_fp(ret,stream,close_flag); - return(ret); - } - -BIO_METHOD *BIO_s_file(void) - { - return(&methods_filep); - } - -static int MS_CALLBACK file_new(BIO *bi) - { - bi->init=0; - bi->num=0; - bi->ptr=NULL; - return(1); - } - -static int MS_CALLBACK file_free(BIO *a) - { - if (a == NULL) return(0); - if (a->shutdown) - { - if ((a->init) && (a->ptr != NULL)) - { - fclose((FILE *)a->ptr); - a->ptr=NULL; - } - a->init=0; - } - return(1); - } - -static int MS_CALLBACK file_read(BIO *b, char *out, int outl) - { - int ret=0; - - if (b->init && (out != NULL)) - { - ret=fread(out,1,(int)outl,(FILE *)b->ptr); - } - return(ret); - } - -static int MS_CALLBACK file_write(BIO *b, const char *in, int inl) - { - int ret=0; - - if (b->init && (in != NULL)) - { - if (fwrite(in,(int)inl,1,(FILE *)b->ptr)) - ret=inl; - /* ret=fwrite(in,1,(int)inl,(FILE *)b->ptr); */ - /* according to Tim Hudson , the commented - * out version above can cause 'inl' write calls under - * some stupid stdio implementations (VMS) */ - } - return(ret); - } - -static long MS_CALLBACK file_ctrl(BIO *b, int cmd, long num, void *ptr) - { - long ret=1; - FILE *fp=(FILE *)b->ptr; - FILE **fpp; - char p[4]; - - switch (cmd) - { - case BIO_C_FILE_SEEK: - case BIO_CTRL_RESET: - ret=(long)fseek(fp,num,0); - break; - case BIO_CTRL_EOF: - ret=(long)feof(fp); - break; - case BIO_C_FILE_TELL: - case BIO_CTRL_INFO: - ret=ftell(fp); - break; - case BIO_C_SET_FILE_PTR: - file_free(b); - b->shutdown=(int)num&BIO_CLOSE; - b->ptr=(char *)ptr; - b->init=1; -#if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) - /* Set correct text/binary mode */ - if (num & BIO_FP_TEXT) - _setmode(fileno((FILE *)ptr),_O_TEXT); - else - _setmode(fileno((FILE *)ptr),_O_BINARY); -#elif defined(OPENSSL_SYS_OS2) - if (num & BIO_FP_TEXT) - setmode(fileno((FILE *)ptr), O_TEXT); - else - setmode(fileno((FILE *)ptr), O_BINARY); -#endif - break; - case BIO_C_SET_FILENAME: - file_free(b); - b->shutdown=(int)num&BIO_CLOSE; - if (num & BIO_FP_APPEND) - { - if (num & BIO_FP_READ) - strcpy(p,"a+"); - else strcpy(p,"a"); - } - else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) - strcpy(p,"r+"); - else if (num & BIO_FP_WRITE) - strcpy(p,"w"); - else if (num & BIO_FP_READ) - strcpy(p,"r"); - else - { - BIOerr(BIO_F_FILE_CTRL,BIO_R_BAD_FOPEN_MODE); - ret=0; - break; - } -#if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) - if (!(num & BIO_FP_TEXT)) - strcat(p,"b"); - else - strcat(p,"t"); -#endif - fp=fopen(ptr,p); - if (fp == NULL) - { - SYSerr(SYS_F_FOPEN,get_last_sys_error()); - ERR_add_error_data(5,"fopen('",ptr,"','",p,"')"); - BIOerr(BIO_F_FILE_CTRL,ERR_R_SYS_LIB); - ret=0; - break; - } - b->ptr=(char *)fp; - b->init=1; - break; - case BIO_C_GET_FILE_PTR: - /* the ptr parameter is actually a FILE ** in this case. */ - if (ptr != NULL) - { - fpp=(FILE **)ptr; - *fpp=(FILE *)b->ptr; - } - break; - case BIO_CTRL_GET_CLOSE: - ret=(long)b->shutdown; - break; - case BIO_CTRL_SET_CLOSE: - b->shutdown=(int)num; - break; - case BIO_CTRL_FLUSH: - fflush((FILE *)b->ptr); - break; - case BIO_CTRL_DUP: - ret=1; - break; - - case BIO_CTRL_WPENDING: - case BIO_CTRL_PENDING: - case BIO_CTRL_PUSH: - case BIO_CTRL_POP: - default: - ret=0; - break; - } - return(ret); - } - -static int MS_CALLBACK file_gets(BIO *bp, char *buf, int size) - { - int ret=0; - - buf[0]='\0'; - fgets(buf,size,(FILE *)bp->ptr); - if (buf[0] != '\0') - ret=strlen(buf); - return(ret); - } - -static int MS_CALLBACK file_puts(BIO *bp, const char *str) - { - int n,ret; - - n=strlen(str); - ret=file_write(bp,str,n); - return(ret); - } - -#endif /* OPENSSL_NO_STDIO */ - -#endif /* HEADER_BSS_FILE_C */ +{ + BIO *ret; + + if ((ret = BIO_new(BIO_s_file())) == NULL) + return (NULL); + + /* redundant flag, left for documentation purposes */ + BIO_set_flags(ret, BIO_FLAGS_UPLINK); + BIO_set_fp(ret, stream, close_flag); + return (ret); +} + +const BIO_METHOD *BIO_s_file(void) +{ + return (&methods_filep); +} + +static int file_new(BIO *bi) +{ + bi->init = 0; + bi->num = 0; + bi->ptr = NULL; + bi->flags = BIO_FLAGS_UPLINK; /* default to UPLINK */ + return (1); +} + +static int file_free(BIO *a) +{ + if (a == NULL) + return (0); + if (a->shutdown) { + if ((a->init) && (a->ptr != NULL)) { + if (a->flags & BIO_FLAGS_UPLINK) + UP_fclose(a->ptr); + else + fclose(a->ptr); + a->ptr = NULL; + a->flags = BIO_FLAGS_UPLINK; + } + a->init = 0; + } + return (1); +} + +static int file_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (b->init && (out != NULL)) { + if (b->flags & BIO_FLAGS_UPLINK) + ret = UP_fread(out, 1, (int)outl, b->ptr); + else + ret = fread(out, 1, (int)outl, (FILE *)b->ptr); + if (ret == 0 + && (b->flags & BIO_FLAGS_UPLINK) ? UP_ferror((FILE *)b->ptr) : + ferror((FILE *)b->ptr)) { + SYSerr(SYS_F_FREAD, get_last_sys_error()); + BIOerr(BIO_F_FILE_READ, ERR_R_SYS_LIB); + ret = -1; + } + } + return (ret); +} + +static int file_write(BIO *b, const char *in, int inl) +{ + int ret = 0; + + if (b->init && (in != NULL)) { + if (b->flags & BIO_FLAGS_UPLINK) + ret = UP_fwrite(in, (int)inl, 1, b->ptr); + else + ret = fwrite(in, (int)inl, 1, (FILE *)b->ptr); + if (ret) + ret = inl; + /* ret=fwrite(in,1,(int)inl,(FILE *)b->ptr); */ + /* + * according to Tim Hudson , the commented out + * version above can cause 'inl' write calls under some stupid stdio + * implementations (VMS) + */ + } + return (ret); +} + +static long file_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + FILE *fp = (FILE *)b->ptr; + FILE **fpp; + char p[4]; + + switch (cmd) { + case BIO_C_FILE_SEEK: + case BIO_CTRL_RESET: + if (b->flags & BIO_FLAGS_UPLINK) + ret = (long)UP_fseek(b->ptr, num, 0); + else + ret = (long)fseek(fp, num, 0); + break; + case BIO_CTRL_EOF: + if (b->flags & BIO_FLAGS_UPLINK) + ret = (long)UP_feof(fp); + else + ret = (long)feof(fp); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + if (b->flags & BIO_FLAGS_UPLINK) + ret = UP_ftell(b->ptr); + else + ret = ftell(fp); + break; + case BIO_C_SET_FILE_PTR: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + b->ptr = ptr; + b->init = 1; +# if BIO_FLAGS_UPLINK!=0 +# if defined(__MINGW32__) && defined(__MSVCRT__) && !defined(_IOB_ENTRIES) +# define _IOB_ENTRIES 20 +# endif + /* Safety net to catch purely internal BIO_set_fp calls */ +# if defined(_MSC_VER) && _MSC_VER>=1900 + if (ptr == stdin || ptr == stdout || ptr == stderr) + BIO_clear_flags(b, BIO_FLAGS_UPLINK); +# elif defined(_IOB_ENTRIES) + if ((size_t)ptr >= (size_t)stdin && + (size_t)ptr < (size_t)(stdin + _IOB_ENTRIES)) + BIO_clear_flags(b, BIO_FLAGS_UPLINK); +# endif +# endif +# ifdef UP_fsetmod + if (b->flags & BIO_FLAGS_UPLINK) + UP_fsetmod(b->ptr, (char)((num & BIO_FP_TEXT) ? 't' : 'b')); + else +# endif + { +# if defined(OPENSSL_SYS_WINDOWS) + int fd = _fileno((FILE *)ptr); + if (num & BIO_FP_TEXT) + _setmode(fd, _O_TEXT); + else + _setmode(fd, _O_BINARY); +# elif defined(OPENSSL_SYS_MSDOS) + int fd = fileno((FILE *)ptr); + /* Set correct text/binary mode */ + if (num & BIO_FP_TEXT) + _setmode(fd, _O_TEXT); + /* Dangerous to set stdin/stdout to raw (unless redirected) */ + else { + if (fd == STDIN_FILENO || fd == STDOUT_FILENO) { + if (isatty(fd) <= 0) + _setmode(fd, _O_BINARY); + } else + _setmode(fd, _O_BINARY); + } +# elif defined(OPENSSL_SYS_WIN32_CYGWIN) + int fd = fileno((FILE *)ptr); + if (num & BIO_FP_TEXT) + setmode(fd, O_TEXT); + else + setmode(fd, O_BINARY); +# endif + } + break; + case BIO_C_SET_FILENAME: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + if (num & BIO_FP_APPEND) { + if (num & BIO_FP_READ) + OPENSSL_strlcpy(p, "a+", sizeof p); + else + OPENSSL_strlcpy(p, "a", sizeof p); + } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) + OPENSSL_strlcpy(p, "r+", sizeof p); + else if (num & BIO_FP_WRITE) + OPENSSL_strlcpy(p, "w", sizeof p); + else if (num & BIO_FP_READ) + OPENSSL_strlcpy(p, "r", sizeof p); + else { + BIOerr(BIO_F_FILE_CTRL, BIO_R_BAD_FOPEN_MODE); + ret = 0; + break; + } +# if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32_CYGWIN) + if (!(num & BIO_FP_TEXT)) + strcat(p, "b"); + else + strcat(p, "t"); +# endif + fp = file_fopen(ptr, p); + if (fp == NULL) { + SYSerr(SYS_F_FOPEN, get_last_sys_error()); + ERR_add_error_data(5, "fopen('", ptr, "','", p, "')"); + BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); + ret = 0; + break; + } + b->ptr = fp; + b->init = 1; + BIO_clear_flags(b, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage + * UPLINK */ + break; + case BIO_C_GET_FILE_PTR: + /* the ptr parameter is actually a FILE ** in this case. */ + if (ptr != NULL) { + fpp = (FILE **)ptr; + *fpp = (FILE *)b->ptr; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_FLUSH: + if (b->flags & BIO_FLAGS_UPLINK) + UP_fflush(b->ptr); + else + fflush((FILE *)b->ptr); + break; + case BIO_CTRL_DUP: + ret = 1; + break; + + case BIO_CTRL_WPENDING: + case BIO_CTRL_PENDING: + case BIO_CTRL_PUSH: + case BIO_CTRL_POP: + default: + ret = 0; + break; + } + return (ret); +} + +static int file_gets(BIO *bp, char *buf, int size) +{ + int ret = 0; + + buf[0] = '\0'; + if (bp->flags & BIO_FLAGS_UPLINK) { + if (!UP_fgets(buf, size, bp->ptr)) + goto err; + } else { + if (!fgets(buf, size, (FILE *)bp->ptr)) + goto err; + } + if (buf[0] != '\0') + ret = strlen(buf); + err: + return (ret); +} + +static int file_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = file_write(bp, str, n); + return (ret); +} + +#else + +static int file_write(BIO *b, const char *in, int inl) +{ + return -1; +} +static int file_read(BIO *b, char *out, int outl) +{ + return -1; +} +static int file_puts(BIO *bp, const char *str) +{ + return -1; +} +static int file_gets(BIO *bp, char *buf, int size) +{ + return 0; +} +static long file_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + return 0; +} +static int file_new(BIO *bi) +{ + return 0; +} +static int file_free(BIO *a) +{ + return 0; +} + +static const BIO_METHOD methods_filep = { + BIO_TYPE_FILE, + "FILE pointer", + file_write, + file_read, + file_puts, + file_gets, + file_ctrl, + file_new, + file_free, + NULL, +}; + +const BIO_METHOD *BIO_s_file(void) +{ + return (&methods_filep); +} + +BIO *BIO_new_file(const char *filename, const char *mode) +{ + return NULL; +} +# endif /* OPENSSL_NO_STDIO */ +#endif /* HEADER_BSS_FILE_C */