socket-ssl.c (4005B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21 22#include "guacamole/mem.h" 23#include "guacamole/error.h" 24#include "guacamole/socket-ssl.h" 25#include "guacamole/socket.h" 26#include "wait-fd.h" 27 28#include <stdlib.h> 29 30#include <openssl/ssl.h> 31 32static ssize_t __guac_socket_ssl_read_handler(guac_socket* socket, 33 void* buf, size_t count) { 34 35 /* Read from socket */ 36 guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; 37 int retval; 38 39 retval = SSL_read(data->ssl, buf, count); 40 41 /* Record errors in guac_error */ 42 if (retval <= 0) { 43 guac_error = GUAC_STATUS_SEE_ERRNO; 44 guac_error_message = "Error reading data from secure socket"; 45 } 46 47 return retval; 48 49} 50 51static ssize_t __guac_socket_ssl_write_handler(guac_socket* socket, 52 const void* buf, size_t count) { 53 54 /* Write data to socket */ 55 guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; 56 int retval; 57 58 retval = SSL_write(data->ssl, buf, count); 59 60 /* Record errors in guac_error */ 61 if (retval <= 0) { 62 guac_error = GUAC_STATUS_SEE_ERRNO; 63 guac_error_message = "Error writing data to secure socket"; 64 } 65 66 return retval; 67 68} 69 70static int __guac_socket_ssl_select_handler(guac_socket* socket, int usec_timeout) { 71 72 guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; 73 int retval = guac_wait_for_fd(data->fd, usec_timeout); 74 75 /* Properly set guac_error */ 76 if (retval < 0) { 77 guac_error = GUAC_STATUS_SEE_ERRNO; 78 guac_error_message = "Error while waiting for data on secure socket"; 79 } 80 81 else if (retval == 0) { 82 guac_error = GUAC_STATUS_TIMEOUT; 83 guac_error_message = "Timeout while waiting for data on secure socket"; 84 } 85 86 return retval; 87 88} 89 90static int __guac_socket_ssl_free_handler(guac_socket* socket) { 91 92 /* Shutdown SSL */ 93 guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; 94 SSL_shutdown(data->ssl); 95 SSL_free(data->ssl); 96 97 /* Close file descriptor */ 98 close(data->fd); 99 100 guac_mem_free(data); 101 return 0; 102} 103 104guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd) { 105 106 /* Create new SSL structure */ 107 SSL* ssl = SSL_new(context); 108 if (ssl == NULL) 109 return NULL; 110 111 /* Allocate socket and associated data */ 112 guac_socket* socket = guac_socket_alloc(); 113 guac_socket_ssl_data* data = guac_mem_alloc(sizeof(guac_socket_ssl_data)); 114 115 /* Init SSL */ 116 data->context = context; 117 data->ssl = ssl; 118 SSL_set_fd(data->ssl, fd); 119 120 /* Accept SSL connection, handle errors */ 121 if (SSL_accept(ssl) <= 0) { 122 123 guac_error = GUAC_STATUS_INTERNAL_ERROR; 124 guac_error_message = "SSL accept failed"; 125 126 guac_mem_free(data); 127 guac_socket_free(socket); 128 SSL_free(ssl); 129 return NULL; 130 } 131 132 /* Store file descriptor as socket data */ 133 data->fd = fd; 134 socket->data = data; 135 136 /* Set read/write handlers */ 137 socket->read_handler = __guac_socket_ssl_read_handler; 138 socket->write_handler = __guac_socket_ssl_write_handler; 139 socket->select_handler = __guac_socket_ssl_select_handler; 140 socket->free_handler = __guac_socket_ssl_free_handler; 141 142 return socket; 143 144} 145