diff options
Diffstat (limited to 'src/SWIG/_bio.i')
-rw-r--r-- | src/SWIG/_bio.i | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/src/SWIG/_bio.i b/src/SWIG/_bio.i new file mode 100644 index 0000000..84b76b3 --- /dev/null +++ b/src/SWIG/_bio.i @@ -0,0 +1,545 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. + * + * Portions created by Open Source Applications Foundation (OSAF) are + * Copyright (C) 2004-2005 OSAF. All Rights Reserved. + * Author: Heikki Toivonen + * + * Copyright 2018 Daniel Wozniak. All Rights Reserved.*/ +/* $Id$ */ + +%{ +#include <openssl/bio.h> +%} + +%apply Pointer NONNULL { BIO * }; +%apply Pointer NONNULL { BIO_METHOD * }; + +%rename(bio_s_bio) BIO_s_bio; +extern BIO_METHOD *BIO_s_bio(void); +%rename(bio_s_mem) BIO_s_mem; +extern BIO_METHOD *BIO_s_mem(void); +%rename(bio_s_socket) BIO_s_socket; +extern BIO_METHOD *BIO_s_socket(void); +%rename(bio_f_ssl) BIO_f_ssl; +extern BIO_METHOD *BIO_f_ssl(void); +%rename(bio_f_buffer) BIO_f_buffer; +extern BIO_METHOD *BIO_f_buffer(void); +%rename(bio_f_cipher) BIO_f_cipher; +extern BIO_METHOD *BIO_f_cipher(void); + +%rename(bio_new) BIO_new; +extern BIO *BIO_new(BIO_METHOD *); +%rename(bio_new_socket) BIO_new_socket; +extern BIO *BIO_new_socket(int, int); +%rename(bio_new_fd) BIO_new_pyfd; +%rename(bio_new_pyfd) BIO_new_pyfd; +%rename(bio_free_all) BIO_free_all; +%threadallow BIO_free_all; +extern void BIO_free_all(BIO *); +%rename(bio_dup_chain) BIO_dup_chain; +extern BIO *BIO_dup_chain(BIO *); + +%rename(bio_push) BIO_push; +extern BIO *BIO_push(BIO *, BIO *); +%rename(bio_pop) BIO_pop; +extern BIO *BIO_pop(BIO *); + +%rename(bio_eof) BIO_eof; +extern int BIO_eof(BIO *); + +%constant int bio_noclose = BIO_NOCLOSE; +%constant int bio_close = BIO_CLOSE; +%constant int BIO_FLAGS_READ = 0x01; +%constant int BIO_FLAGS_WRITE = 0x02; +%constant int BIO_FLAGS_IO_SPECIAL = 0x04; +%constant int BIO_FLAGS_RWS = (BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL); +%constant int BIO_FLAGS_SHOULD_RETRY = 0x08; +%constant int BIO_FLAGS_MEM_RDONLY = 0x200; + +%warnfilter(454) _bio_err; +%inline %{ +static PyObject *_bio_err; + + +void pyfd_init(void); + +void bio_init(PyObject *bio_err) { + Py_INCREF(bio_err); + _bio_err = bio_err; + pyfd_init(); +} + +int bio_free(BIO *bio) { + int ret; + + Py_BEGIN_ALLOW_THREADS + ret = BIO_free(bio); + Py_END_ALLOW_THREADS + if (ret == 0) { + m2_PyErr_Msg(_bio_err); + } + return ret; +} + +BIO * bio_new_file(const char *filename, const char *mode) { + BIO *ret; + + Py_BEGIN_ALLOW_THREADS + ret = BIO_new_file(filename, mode); + Py_END_ALLOW_THREADS + + if (ret == NULL) { + m2_PyErr_Msg(_bio_err); + } + + return ret; +} + +BIO *bio_new_pyfile(PyObject *pyfile, int bio_close) { + FILE *fp = NULL; + BIO *bio = NULL; + + fp = PyFile_AsFile(pyfile); + + bio = BIO_new_fp(fp, bio_close); + + /* returns NULL if error occurred */ + if (bio == NULL) { + /* Find out the name of the file so we can have good error + * message. */ + PyObject *pyname = m2_PyFile_Name(pyfile); + char *name = PyBytes_AsString(pyname); + + if (name == NULL) { + PyErr_Format(_bio_err, + "Opening of the new BIO on file failed!"); + } + else { + PyErr_Format(_bio_err, + "Opening of the new BIO on file %s failed!", name); + } + Py_DECREF(pyname); + } + return bio; +} + +PyObject *bio_read(BIO *bio, int num) { + PyObject *blob; + void *buf; + int r; + + if (!(buf = PyMem_Malloc(num))) { + PyErr_SetString(PyExc_MemoryError, "bio_read"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + r = BIO_read(bio, buf, num); + Py_END_ALLOW_THREADS + if (r < 0) { + PyMem_Free(buf); + if (ERR_peek_error()) { + m2_PyErr_Msg(_bio_err); + return NULL; + } + Py_RETURN_NONE; + } + + blob = PyBytes_FromStringAndSize(buf, r); + + PyMem_Free(buf); + return blob; +} + +PyObject *bio_gets(BIO *bio, int num) { + PyObject *blob; + void *buf; + int r; + + if (!(buf = PyMem_Malloc(num))) { + PyErr_SetString(PyExc_MemoryError, "bio_gets"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + r = BIO_gets(bio, buf, num); + Py_END_ALLOW_THREADS + if (r < 1) { + PyMem_Free(buf); + if (ERR_peek_error()) { + m2_PyErr_Msg(_bio_err); + return NULL; + } + Py_RETURN_NONE; + } + + blob = PyBytes_FromStringAndSize(buf, r); + + PyMem_Free(buf); + return blob; +} + +int bio_write(BIO *bio, PyObject *from) { + const void *fbuf; + int flen = 0, ret; + + if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) + return -1; + + Py_BEGIN_ALLOW_THREADS + ret = BIO_write(bio, fbuf, flen); + Py_END_ALLOW_THREADS + if (ret < 0) { + if (ERR_peek_error()) { + m2_PyErr_Msg(_bio_err); + return -1; + } + } + return ret; +} + +/* XXX Casting size_t to int. */ +int bio_ctrl_pending(BIO *bio) { + return (int)BIO_ctrl_pending(bio); +} + +int bio_ctrl_wpending(BIO *bio) { + return (int)BIO_ctrl_wpending(bio); +} + +int bio_ctrl_get_write_guarantee(BIO *a) { + return BIO_ctrl_get_write_guarantee(a); +} + +int bio_reset(BIO *bio) { + return (int)BIO_reset(bio); +} +%} + +%threadallow bio_flush; +%inline %{ +int bio_flush(BIO *bio) { + return (int)BIO_flush(bio); +} + +int bio_seek(BIO *bio, int offset) { + return (int)BIO_seek(bio, offset); +} + +int bio_tell(BIO* bio) { + return BIO_tell(bio); +} + +void bio_set_flags(BIO *bio, int flags) { + BIO_set_flags(bio, flags); +} + +int bio_get_flags(BIO *bio) { + return BIO_get_flags(bio); +} + +/* + * sets the cipher of BIO @param b to c using key @param key and IV @iv. + * @param enc should be set to 1 for encryption and zero to decryption. + * + */ +PyObject *bio_set_cipher(BIO *b, EVP_CIPHER *c, PyObject *key, PyObject *iv, int op) { + const void *kbuf, *ibuf; + Py_ssize_t klen, ilen; + + if ((PyObject_AsReadBuffer(key, &kbuf, &klen) == -1) + || (PyObject_AsReadBuffer(iv, &ibuf, &ilen) == -1)) + return NULL; + + BIO_set_cipher(b, (const EVP_CIPHER *)c, + (unsigned char *)kbuf, (unsigned char *)ibuf, op); + Py_RETURN_NONE; +} + +int bio_set_mem_eof_return(BIO *b, int v) { + return (int)BIO_set_mem_eof_return(b, v); +} + +int bio_get_fd(BIO *bio) { + return BIO_get_fd(bio, NULL); +} +%} + +%warnfilter(454) methods_fdp; +%threadallow bio_do_handshake; +%inline %{ +int bio_do_handshake(BIO *bio) { + return BIO_do_handshake(bio); +} + +/* macro */ +int bio_make_bio_pair(BIO* b1, BIO* b2) { + return BIO_make_bio_pair(b1, b2); +} + +int bio_set_write_buf_size(BIO* b, size_t size) { + return BIO_set_write_buf_size(b, size); +} + +int bio_should_retry(BIO* a) { + return BIO_should_retry(a); +} + +int bio_should_read(BIO* a) { + return BIO_should_read(a); +} + +int bio_should_write(BIO* a) { + return BIO_should_write(a); +} + +/* Macros for things not defined before 1.1.0 */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static BIO_METHOD * +BIO_meth_new( int type, const char *name ) +{ + BIO_METHOD *method = malloc( sizeof(BIO_METHOD) ); + memset( method, 0, sizeof(BIO_METHOD) ); + + method->type = type; + method->name = name; + + return method; +} + +static void +BIO_meth_free( BIO_METHOD *meth ) +{ + if ( meth == NULL ) { + return; + } + + free(meth); +} +#define BIO_meth_set_write(m, f) (m)->bwrite = (f) +#define BIO_meth_set_read(m, f) (m)->bread = (f) +#define BIO_meth_set_puts(m, f) (m)->bputs = (f) +#define BIO_meth_set_gets(m, f) (m)->bgets = (f) +#define BIO_meth_set_ctrl(m, f) (m)->ctrl = (f) +#define BIO_meth_set_create(m, f) (m)->create = (f) +#define BIO_meth_set_destroy(m, f) (m)->destroy = (f) +#define BIO_set_shutdown(b, x) (b)->shutdown = x +#define BIO_get_shutdown(b) (b)->shutdown +#define BIO_set_init(b, x) b->init = x +#define BIO_get_init(b) (b)->init +#define BIO_set_data(b, x) b->ptr = x +#define BIO_clear_flags(b, x) b->flags &= ~(x) +#define BIO_get_data(b) b->ptr +#endif + +/* implment custom BIO_s_pyfd */ + +#ifdef _WIN32 +# define clear_sys_error() SetLastError(0) +/* Linux doesn't use underscored calls yet */ +# define open(p, f, m) _open(p, f, m) +# define read(f, b, n) _read(f, b, n) +# define write(f, b, n) _write(f, b, n) +# define close(f) _close(f) +# define lseek(fd, o, w) _lseek(fd, o, w) +#else +# define clear_sys_error() errno=0 +#endif + +typedef struct pyfd_struct { + int fd; +} BIO_PYFD_CTX; + +/* Setting up methods_fdp */ +static BIO_METHOD *methods_fdp; + +static int pyfd_write(BIO *b, const char *in, int inl) { + int ret, fd; + + if (BIO_get_fd(b, &fd) == -1) { + PyErr_SetString(_bio_err, "BIO has not been initialized."); + return -1; + } + clear_sys_error(); + ret = write(fd, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_write(b); + } + return ret; +} + +static int pyfd_read(BIO *b, char *out, int outl) { + int ret = 0, fd; + + if (BIO_get_fd(b, &fd) == -1) { + PyErr_SetString(_bio_err, "BIO has not been initialized."); + return -1; + } + if (out != NULL) { + clear_sys_error(); + ret = read(fd, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_read(b); + } + } + return ret; +} + +static int pyfd_puts(BIO *bp, const char *str) { + int n, ret; + + n = strlen(str); + ret = pyfd_write(bp, str, n); + return ret; +} + +static int pyfd_gets(BIO *bp, char *buf, int size) { + int ret = 0; + char *ptr = buf; + char *end = buf + size - 1; + + /* See + https://github.com/openssl/openssl/pull/3442 + We were here just repeating a bug from OpenSSL + */ + while (ptr < end && pyfd_read(bp, ptr, 1) > 0) { + if (*ptr++ == '\n') + break; + } + + ptr[0] = '\0'; + + if (buf[0] != '\0') + ret = strlen(buf); + return ret; +} + +static int pyfd_new(BIO* b) { + BIO_PYFD_CTX* ctx; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return 0; + + ctx->fd = -1; + + BIO_set_data(b, ctx); + BIO_set_shutdown(b, 0); + BIO_set_init(b, 1); + + return 1; + } + +static int pyfd_free(BIO* b) { + BIO_PYFD_CTX* ctx; + + if (b == 0) + return 0; + + ctx = BIO_get_data(b); + if (ctx == NULL) + return 0; + + if (BIO_get_shutdown(b) && BIO_get_init(b)) + close(ctx->fd); + + BIO_set_data(b, NULL); + BIO_set_shutdown(b, 0); + BIO_set_init(b, 0); + + OPENSSL_free(ctx); + + return 1; +} + +static long pyfd_ctrl(BIO *b, int cmd, long num, void *ptr) { + BIO_PYFD_CTX* ctx; + int *ip; + long ret = 1; + + ctx = BIO_get_data(b); + if (ctx == NULL) + return 0; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + case BIO_C_FILE_SEEK: + ret = (long)lseek(ctx->fd, num, 0); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = (long)lseek(ctx->fd, 0, 1); + break; + case BIO_C_SET_FD: + pyfd_free(b); + if (*((int *)ptr) > -1) { + if (!pyfd_new(b) || !(ctx = BIO_get_data(b))) + return 0; + ctx->fd = *((int *)ptr); + BIO_set_shutdown(b, (int)num); + BIO_set_init(b, 1); + } + break; + case BIO_C_GET_FD: + if (BIO_get_init(b)) { + ip = (int *)ptr; + if (ip != NULL) + *ip = ctx->fd; + ret = ctx->fd; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = BIO_get_shutdown(b); + break; + case BIO_CTRL_SET_CLOSE: + BIO_set_shutdown(b, (int)num); + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +void pyfd_init(void) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + methods_fdp = BIO_meth_new( + BIO_get_new_index()|BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK, + "python file descriptor"); +#else + methods_fdp = BIO_meth_new( + 100 |BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK, + "python file descriptor"); +#endif + + BIO_meth_set_write(methods_fdp, pyfd_write); + BIO_meth_set_read(methods_fdp, pyfd_read); + BIO_meth_set_puts(methods_fdp, pyfd_puts); + BIO_meth_set_gets(methods_fdp, pyfd_gets); + BIO_meth_set_ctrl(methods_fdp, pyfd_ctrl); + BIO_meth_set_create(methods_fdp, pyfd_new); + BIO_meth_set_destroy(methods_fdp, pyfd_free); +} + +BIO* BIO_new_pyfd(int fd, int close_flag) { + BIO *ret; + + ret = BIO_new(methods_fdp); + BIO_set_fd(ret, fd, close_flag); + return ret; + } +%} + |