I am trying to get the SSL/TLS client with OpenSSL from here: https://wiki.openssl.org/index.php/SSL/TLS_Client to build and run in visual studio.
I have it successfully building in visual studio, but it won't run successfully.
Currently it will run to res = BIO_do_connect(web); andssl_err = ERR_get_error(); eventually failing at the following if (!(1 == res)) the console output is bad hostname lookup
I've looked around to try and find some solution, but nothing seems effective.
The H file I'm using is pretty much the same as the one at the openssl.org. with the exception of the addition of
typedef struct {
int status_code;
char *reason;
char *content;
} HttpResponse;
This is pretty much my first run in C, I've done Java before, so if someone has any insight, that would be great. Or if they can point to an example of an https post request for Windows in C.
#include "openssl-bio-fetch.h"
#include "corecrt_wstdio.h"
#ifndef HEADER_X509_H
#include <openssl/x509.h>
/* openssl/x509.h ends up #include-ing this file at about the only
* appropriate moment. */
#endif
int verify_callback(int preverify, X509_STORE_CTX* x509_ctx);
void init_openssl_library(void);
void print_cn_name(const char* label, X509_NAME* const name);
void print_san_name(const char* label, X509* const cert);
void print_error_string(unsigned long err, const char* const label);
const char* const PREFERRED_CIPHERS = "HIGH:!aNULL:!kRSA:!SRP:!PSK:!CAMELLIA:!RC4:!MD5:!DSS";
#if 0
const char* const PREFERRED_CIPHERS = "kEECDH:kEDH:kRSA:AESGCM:AES256:AES128:3DES:SHA256:SHA84:SHA1:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM!ADH:!AECDH";
#endif
#if 0
const char* const PREFERRED_CIPHERS = NULL;
#endif
#if 0
const char* PREFERRED_CIPHERS =
/* TLS 1.2 only */
"ECDHE-ECDSA-AES256-GCM-SHA384:"
"ECDHE-RSA-AES256-GCM-SHA384:"
"ECDHE-ECDSA-AES128-GCM-SHA256:"
"ECDHE-RSA-AES128-GCM-SHA256:"
/* TLS 1.2 only */
"DHE-DSS-AES256-GCM-SHA384:"
"DHE-RSA-AES256-GCM-SHA384:"
"DHE-DSS-AES128-GCM-SHA256:"
"DHE-RSA-AES128-GCM-SHA256:"
/* TLS 1.0 only */
"DHE-DSS-AES256-SHA:"
"DHE-RSA-AES256-SHA:"
"DHE-DSS-AES128-SHA:"
"DHE-RSA-AES128-SHA:"
/* SSL 3.0 and TLS 1.0 */
"EDH-DSS-DES-CBC3-SHA:"
"EDH-RSA-DES-CBC3-SHA:"
"DH-DSS-DES-CBC3-SHA:"
"DH-RSA-DES-CBC3-SHA";
#endif
void add_char_header(char *current, char *key, char *value)
{
strcat(current, "\r\n");
strcat(current, key);
strcat(current, ": ");
strcat(current, value);
}
void add_int_header(char *current, char *key, int value)
{
char *buffer = malloc(5);
sprintf(buffer, "%d", value);
strcat(current, "\r\n");
strcat(current, key);
strcat(current, ": ");
strcat(current, buffer);
free(buffer);
}
void parse_http_response(char *resp, HttpResponse *response)
{
response.reason = "";
response.content = "";
}
char * buildRequest(char *request) {
size_t size;
size = strlen("{\"client_ip\":\"10.20.30.40\"}");
strcpy(request, "{\"client_ip\":\"10.20.30.40\"}");
printf("pks-368\n");
return request;
}
int
main(int ac, char **av)
{
char *request = malloc(225);
buildRequest(request);
HttpResponse response;
response.reason = calloc(1, 64);
response.content = calloc(1, 10 * 1024);
response.status_code = 0;
int a = openssl_fetch(request, &response);
fprintf(stderr, "C %d", response.status_code);
fprintf(stderr, "A %s", response.content);
fprintf(stderr, "B %s", response.reason);
printf("Paused");
}
int openssl_fetch(char *request, HttpResponse *response)
{
char *HOST_NAME = "google.com";
char *HOST_PORT = "443";
char *hostname = calloc(1, 100);
strcpy(hostname, HOST_NAME);
strcat(hostname, ":");
strcat(hostname, HOST_PORT);
long res = 1;
int ret = 1;
unsigned long ssl_err = 0;
SSL_CTX* ctx = NULL;
BIO *web = NULL, *out = NULL;
SSL *ssl = NULL;
do {
init_openssl_library();
const SSL_METHOD* method = SSLv23_method();
ssl_err = ERR_get_error();
if (!(NULL != method))
{
print_error_string(ssl_err, "SSLv23_method");
break; /* failed */
}
ctx = SSL_CTX_new(method);
ssl_err = ERR_get_error();
if (!(ctx != NULL))
{
print_error_string(ssl_err, "SSL_CTX_new");
break; /* failed */
}
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
SSL_CTX_set_verify_depth(ctx, 5);
const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
long old_opts = SSL_CTX_set_options(ctx, flags);
UNUSED(old_opts);
const char *file_loc = "C:\\Users\\$USER\\Desktop\\trusted-roots.pem";
res = SSL_CTX_load_verify_locations(ctx, file_loc, NULL);
ssl_err = ERR_get_error();
if (!(1 == res))
{
fprintf(stderr, "SSL_CTX_load_verify_locations -- [%s]\n", ssl_err);
}
web = BIO_new_ssl_connect(ctx);
ssl_err = ERR_get_error();
if (!(web != NULL))
{
print_error_string(ssl_err, "BIO_new_ssl_connect");
break; /* failed */
}
res = BIO_set_conn_hostname(web, hostname);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "BIO_set_conn_hostname");
break; /* failed */
}
BIO_get_ssl(web, &ssl);
ssl_err = ERR_get_error();
if (!(ssl != NULL))
{
print_error_string(ssl_err, "BIO_get_ssl");
break; /* failed */
}
res = SSL_set_cipher_list(ssl, PREFERRED_CIPHERS);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "SSL_set_cipher_list");
break; /* failed */
}
res = SSL_set_tlsext_host_name(ssl, HOST_NAME);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "SSL_set_tlsext_host_name");
}
out = BIO_new_fp(stdout, BIO_NOCLOSE);
ssl_err = ERR_get_error();
if (!(NULL != out))
{
print_error_string(ssl_err, "BIO_new_fp");
break; /* failed */
}
res = BIO_do_connect(web);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "BIO_do_connect");
break; /* failed */
}
res = BIO_do_handshake(web);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "BIO_do_handshake");
break; /* failed */
}
X509* cert = SSL_get_peer_certificate(ssl);
if (cert) { X509_free(cert); } /* Free immediately */
if (NULL == cert)
{
print_error_string(X509_V_ERR_APPLICATION_VERIFICATION, "SSL_get_peer_certificate");
break; /* failed */
}
res = SSL_get_verify_result(ssl);
if (!(X509_V_OK == res))
{
print_error_string((unsigned long)res, "SSL_get_verify_results");
break; /* failed */
}
char message[2048];
strcpy(message, "POST ");
strcat(message, HOST_RESOURCE);
strcat(message, " HTTP/1.1 ");
add_char_header(message, "Host", HOST_NAME);
add_char_header(message, "Connection", "close");
add_char_header(message, "Accept", "*/*");
add_int_header(message, "Content-Length", (int)strlen(request));
strcat(message, "\r\n\r\n");
strcat(message, request);
BIO_puts(web, message);
char buff[6144] = { 0 };
int len = 0;
do {
len = BIO_read(web, buff, sizeof(buff));
} while (len > 0 || BIO_should_retry(web));
ret = 0;
parse_http_response(buff, response);
free(hostname);
} while (0);
if (out)
BIO_free(out);
if (web != NULL)
BIO_free_all(web);
if (NULL != ctx)
SSL_CTX_free(ctx);
return ret;
}
void init_openssl_library(void)
{
(void)SSL_library_init();
SSL_load_error_strings();
#if defined (OPENSSL_THREADS)
// fprintf(stdout, "Warning: thread locking is not implemented\n");
#endif
}
void print_cn_name(const char* label, X509_NAME* const name)
{
int idx = -1, success = 0;
unsigned char *utf8 = NULL;
do
{
if (!name) break; /* failed */
idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
if (!(idx > -1)) break; /* failed */
X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
if (!entry) break; /* failed */
ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
if (!data) break; /* failed */
int length = ASN1_STRING_to_UTF8(&utf8, data);
if (!utf8 || !(length > 0)) break; /* failed */
fprintf(stdout, " %s: %s\n", label, utf8);
success = 1;
} while (0);
if (utf8)
OPENSSL_free(utf8);
if (!success)
fprintf(stdout, " %s: <not available>\n", label);
}
void print_san_name(const char* label, X509* const cert)
{
int success = 0;
GENERAL_NAMES* names = NULL;
unsigned char* utf8 = NULL;
do
{
if (!cert) break; /* failed */
names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
if (!names) break;
int i = 0, count = sk_GENERAL_NAME_num(names);
if (!count) break; /* failed */
for (i = 0; i < count; ++i)
{
GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
if (!entry) continue;
if (GEN_DNS == entry->type)
{
int len1 = 0, len2 = -1;
len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
if (utf8) {
len2 = (int)strlen((const char*)utf8);
}
if (len1 != len2) {
fprintf(stderr, " Strlen and ASN1_STRING size do not match (embedded null?): %d vs %d\n", len2, len1);
}
if (utf8 && len1 && len2 && (len1 == len2)) {
fprintf(stdout, " %s: %s\n", label, utf8);
success = 1;
}
if (utf8) {
OPENSSL_free(utf8), utf8 = NULL;
}
}
else
{
fprintf(stderr, " Unknown GENERAL_NAME type: %d\n", entry->type);
}
}
} while (0);
if (names)
GENERAL_NAMES_free(names);
if (utf8)
OPENSSL_free(utf8);
if (!success)
fprintf(stdout, " %s: <not available>\n", label);
}
int verify_callback(int preverify, X509_STORE_CTX* x509_ctx)
{
int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
int err = X509_STORE_CTX_get_error(x509_ctx);
if (depth == 0) {
}
if (preverify == 0)
{
if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
fprintf(stdout, " Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY\n");
else if (err == X509_V_ERR_CERT_UNTRUSTED)
fprintf(stdout, " Error = X509_V_ERR_CERT_UNTRUSTED\n");
else if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
fprintf(stdout, " Error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN\n");
else if (err == X509_V_ERR_CERT_NOT_YET_VALID)
fprintf(stdout, " Error = X509_V_ERR_CERT_NOT_YET_VALID\n");
else if (err == X509_V_ERR_CERT_HAS_EXPIRED)
fprintf(stdout, " Error = X509_V_ERR_CERT_HAS_EXPIRED\n");
else if (err == X509_V_OK)
fprintf(stdout, " Error = X509_V_OK\n");
else
fprintf(stdout, " Error = %d\n", err);
}
#if !defined(NDEBUG)
return 1;
#else
return preverify;
#endif
}
void print_error_string(unsigned long err, const char* const label)
{
const char* const str = ERR_reason_error_string(err);
if (str)
fprintf(stderr, "%s\n", str);
else
fprintf(stderr, "%s failed: %lu (0x%lx)\n", label, err, err);
}
Related
I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <getopt.h>
#include <stdbool.h>
#include <curl/curl.h>
#include <pthread.h>
#define BUFFER_SIZE 1024
#define SW_URL_STR_lEN 255
struct test_url {
char protocol[SW_URL_STR_lEN];
char hostname[SW_URL_STR_lEN];
char page[SW_URL_STR_lEN];
int port;
};
typedef struct test_url test_url_t;
test_url_t *test_create_url();
void test_destroy_url(test_url_t *url);
bool test_parse_url(test_url_t *url, const char *to_parse);
static int _getch(void) {
struct termios oldt, newt;
int ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) {
(void) ptr;
if (size * nmemb > BUFFER_SIZE) {
fprintf(stdout, "Error buffer too small");
exit(EXIT_FAILURE);
}
char *buf = (char *) userdata;
strncpy(buf, ptr, size * nmemb);
return size * nmemb;
}
static void send_rtsp_options_request(CURL *handle, const char *uri) {
fprintf(stdout, "\nRTSP: OPTIONS %s\n", uri);
curl_easy_setopt(handle, CURLOPT_RTSP_STREAM_URI, uri);
curl_easy_setopt(handle, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
curl_easy_perform(handle);
}
static void send_rtsp_describe_request(CURL *handle, const char *uri, char *str_sdp) {
fprintf(stdout, "\nRTSP: DESCRIBE %s\n", uri);
fprintf(stdout, " describe: %s", str_sdp);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, str_sdp);
curl_easy_setopt(handle, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_DESCRIBE);
curl_easy_perform(handle);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, stdout);
}
static void send_rtsp_setup_request(CURL *handle, const char *uri, const char *transport) {
fprintf(stdout, "\nRTSP: SETUP %s\n", uri);
fprintf(stdout, " TRANSPORT %s\n", transport);
curl_easy_setopt(handle, CURLOPT_RTSP_STREAM_URI, uri);
curl_easy_setopt(handle, CURLOPT_RTSP_TRANSPORT, transport);
curl_easy_setopt(handle, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
curl_easy_perform(handle);
}
static void send_rtsp_play_request(CURL *handle, const char *uri, const char *range) {
fprintf(stdout, "\nRTSP: PLAY %s\n", uri);
curl_easy_setopt(handle, CURLOPT_RTSP_STREAM_URI, uri);
curl_easy_setopt(handle, CURLOPT_RANGE, range);
curl_easy_setopt(handle, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
curl_easy_perform(handle);
/* Disable ranges */
curl_easy_setopt(handle, CURLOPT_RANGE, NULL);
}
// static void send_rtsp_pause_request(CURL *handken, const char *uri, const char *range) {
// fprintf(stdout, "\nRTSP: PAUSE %s\n", uri);
// curl_easy_setopt(handle, CURLOPT_RTSP_STREAM_URI, uri);
// curl_easy_setopt(handle, CURLOPT_RANGE, range);
// curl_easy_setopt(handle, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PAUSE);
// curl_easy_perform(handle);
// /* Disable ranges */
// curl_easy_setopt(handle, CURLOPT_RANGE, NULL);
// }
static void send_rtsp_teardown_request(CURL *handle, const char *uri) {
fprintf(stdout, "\nRTSP: TEARDOWN %s\n", uri);
curl_easy_setopt(handle, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
curl_easy_perform(handle);
}
/* Main options */
typedef enum {
rtsp_injector_arg_help = 'h',
rtsp_injector_arg_addr = 'a',
rtsp_injector_arg_verbose = 'v',
} rtsp_injector_arg_t;
static void rtsp_print_help() {
fprintf(stdout, "Usage: \n");
fprintf(stdout, "\t-%c, --help\n", rtsp_injector_arg_help);
fprintf(stdout, "\t\tprints this help, and exits\n");
fprintf(stdout, "\n");
fprintf(stdout, "\t-%c, --rtsp-addr\n", rtsp_injector_arg_addr);
fprintf(stdout, "\t\tThe rtsp address of the server, with the port and the right camera choice such as \
\n\t\tActive camera - 'rtsp://(device ip address):5554/camera' \
\n\t\tBack camera - 'rtsp://(device ip address):5554/back' \
\n\t\tFront camera - 'rtsp://(device ip address):5554/front'\n");
fprintf(stdout, "\n");
fprintf(stdout, "\t-%c, --verbose\n", rtsp_injector_arg_verbose);
fprintf(stdout, "\t\tprints more details in the packets trading\n");
fprintf(stdout, "\n");
}
static void *pthread_proc(void *arg) {
(void)arg;
fprintf(stdout, "COIN COIN\n");
return NULL;
}
int main(int argc, char **argv) {
if (argc < 2) {
rtsp_print_help();
return EXIT_FAILURE;
}
static struct option long_options[] = {
{"help", no_argument, NULL, rtsp_injector_arg_help },
{"rtsp-addr", required_argument, NULL, rtsp_injector_arg_addr },
{"verbose", no_argument, NULL, rtsp_injector_arg_verbose },
{ NULL, 0, NULL, 0 },
};
int option_index = 0;
int c = 0;
char opstring[1024] = {0};
size_t s = 0;
pthread_t thrd;
// pthread_create(&thrd, NULL, pthread_proc, NULL);
s += snprintf(opstring + s, sizeof(opstring) - s, "%c", rtsp_injector_arg_help);
s += snprintf(opstring + s, sizeof(opstring) - s, "%c:", rtsp_injector_arg_addr);
s += snprintf(opstring + s, sizeof(opstring) - s, "%c", rtsp_injector_arg_verbose);
long verbose_is_on = 0L;
char *url = NULL;
while ((c = getopt_long(argc, argv, opstring, long_options, &option_index)) != -1) {
switch (c) {
case rtsp_injector_arg_help:
rtsp_print_help();
return EXIT_SUCCESS;
case rtsp_injector_arg_addr:
url = optarg;
break;
case rtsp_injector_arg_verbose:
verbose_is_on = 1L;
break;
default:
fprintf(stdout, "Invalid option 0%o: '%c' ??\n", c, c);
rtsp_print_help();
return EXIT_FAILURE;
}
}
if (url == NULL) {
fprintf(stdout, "Missing mandatory prefix '-a' to the server address\n");
rtsp_print_help();
return EXIT_FAILURE;
}
int res = 0;
/* Where the PLAY starts and when should it ends */
const char *range = "0.000-";
char uri[1024] = {0};
// char control[1024] = {0};
char str_sdp[BUFFER_SIZE] = {0};
/* Initialize all libcurl sub moduless */
res = curl_global_init(CURL_GLOBAL_ALL);
if (res != CURLE_OK) {
fprintf(stdout, "curl_global_init failed\n");
return EXIT_FAILURE;
}
/* Create a sesion handle */
CURL *my_handle = curl_easy_init();
if (my_handle == NULL) {
fprintf(stdout, "curl_easy_init failed\n");
return EXIT_FAILURE;
}
/* Set the url to work with, must to be the right format ie RFC , the function doesn't check it */
curl_easy_setopt(my_handle, CURLOPT_URL, url);
/* Parse server information ie ip and port */
test_url_t *my_url = test_create_url();
test_parse_url(my_url, url);
fprintf(stdout, "Protocol: %s\nHostname: %s\nPort: %d\nPage: %s\n",
my_url->protocol, my_url->hostname, my_url->port, my_url->page);
curl_easy_setopt(my_handle, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(my_handle, CURLOPT_HEADERDATA, stdout);
curl_easy_setopt(my_handle, CURLOPT_USERAGENT, "test-client-rtsp");
curl_easy_setopt(my_handle, CURLOPT_VERBOSE, verbose_is_on);
/* Let's send some requests */
snprintf(uri, sizeof(uri), "%s", url);
/* OPTIONS */
send_rtsp_options_request(my_handle, uri);
/* DESCRIBE */
send_rtsp_describe_request(my_handle, uri, str_sdp);
fprintf(stdout, "Sdp information:\n%s", str_sdp);
// char *transport = "RTP/AVP/TCP;unicast;client_port=1234-1235";
char transport[1024] = "RTP/AVP;unicast;client_port=1234-1235";
fprintf(stdout, "Transport: %s", transport);
/* SETUP */
snprintf(uri, sizeof(uri), "%s", url);
strncat(uri, "/trackID=0", strlen(uri)); /* Different url for SETUP, check doc in trac with the scenari exemple */
send_rtsp_setup_request(my_handle, uri, transport);
/* PLAY */
snprintf(uri, sizeof(uri), "%s", url);
send_rtsp_play_request(my_handle, uri, range);
pthread_create(&thrd, NULL, pthread_proc, NULL);
_getch();
/* TEARDOWN */
send_rtsp_teardown_request(my_handle, uri);
/* Destroy the session handle */
curl_easy_cleanup(my_handle);
/* Cleanup curl init resources */
curl_global_cleanup();
test_destroy_url(my_url);
return EXIT_SUCCESS;
}
test_url_t * test_create_url() {
test_url_t *ret = NULL;
ret = malloc(sizeof(test_url_t));
if (!ret) {
return NULL;
}
memset(ret, 0, sizeof(test_url_t));
return ret;
}
void test_destroy_url(test_url_t *url) {
free(url);
}
bool test_parse_url(test_url_t *url, const char *to_parse) {
int pos_of_hostname = 0, pos_port = 0, pos_page = 0;
const char *hostname = NULL;
const char *str_port = NULL;
const char *str_page = NULL;
char str_port_number[4];
if (to_parse == NULL) {
return false;
}
hostname = strstr(to_parse, "://");
if (hostname == NULL) {
return false;
}
pos_of_hostname = hostname - to_parse; /* Get the position of "://" */
if (pos_of_hostname > (int)sizeof(url->protocol)) {
return false;
}
strncpy(url->protocol, to_parse, sizeof(url->protocol));
url->protocol[pos_of_hostname] = '\0';
hostname = to_parse + pos_of_hostname + 3; /* Skip protocol and '://' */
/* Check if port is provided */
str_port = strstr(hostname, ":");
if (str_port != NULL) {
pos_port = str_port - hostname;
strncpy(url->hostname, hostname, sizeof(url->hostname));
url->hostname[pos_port] = '\0';
str_page = strstr(hostname, "/");
if (str_page != NULL) { /* Check if page is provided */
pos_page = str_page - hostname;
str_page = hostname + pos_page + 1;
strncpy(url->page, str_page, sizeof(url->page));
if (pos_port < pos_page) { /* Check if ':' is before '/' ex: ':8080/something' */
strncpy(url->hostname, hostname, sizeof(url->hostname));
url->hostname[pos_port] = '\0';
/* Port number is provided */
str_page = hostname + pos_port + 1; /* Skip hostname and the ':' before port number' */
strncpy(str_port_number, str_page, sizeof(str_port_number));
url->port = atoi(str_port_number);
}
else { /* Page provided before port */
/* Warning: strncpy doesn't put a '\0' at the end of the string if src doesn't have one*/
strncpy(url->hostname, hostname, sizeof(url->hostname));
url->hostname[pos_page] = '\0';
}
}
else { /* There is no page provided */
str_page = hostname + pos_port + 1;
strncpy(str_port_number, str_page, sizeof(str_port_number));
url->port = atoi(str_port_number);
}
}
else { /* Only page provided */
str_page = strstr(hostname, "/");
if (str_page != NULL) { /* Check if page is provided */
pos_page = str_page - hostname;
str_page = hostname + pos_page + 1;
strncpy(url->page, str_page, sizeof(url->page));
url->page[strlen(str_page)] = '\0';
strncpy(url->hostname, hostname, sizeof(url->hostname));
url->hostname[pos_page] = '\0';
}
else { /* Case where there is only a hostname provided */
strncpy(url->hostname, hostname, sizeof(url->hostname));
}
}
return true;
}
The code crashes on pthread_create line 256 with the following backtrace:
Program received signal SIGSEGV, Segmentation fault.
__GI__IO_enable_locks () at genops.c:552
552 genops.c: No such file or directory.
(gdb) bt
#0 __GI__IO_enable_locks () at genops.c:552
#1 0x00007ffff7bbe52d in __pthread_create_2_1 (newthread=<optimized out>, attr=0x0, start_routine=<optimized out>, arg=0x0) at pthread_create.c:736
#2 0x0000555555557db5 in main (argc=3, argv=0x7fffffffd988) at test_client_rtsp.c:256
If I uncomment the first pthread_create, and comment the second one, it works fine. I take it this has to do with libcurl, but I'm not too sure it.
Curl 7.64.0 is compiled with:
./configure --disable-shared --enable-static --disable-ldap --disable-sspi --without-librtmp --disable-ftp --disable-file --disable-dict --disable-telnet --disable-tftp --disable-rtsp --disable-pop3 --disable-imap --disable-smtp --disable-gopher --disable-smb --without-libidn --without-zlib --without-ssl --enable-rtsp
I'm kinda lost as to what is going on there.
Im using the following code to parse a CSV and insert the values into a table
void readcsv()
{
FILE* stream = fopen("input.csv", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp = strdup(line);
char a1[20]= "";
char b1[20]= "";
char c1[20]= "";
char d1[20]= "";
char e1[20]= "";
char f1[20]= "";
strcat(a1, getcsvfield(tmp, 1));
strcat(b1, getcsvfield(tmp, 2));
strcat(c1, getcsvfield(tmp, 3));
strcat(d1, getcsvfield(tmp, 4));
strcat(e1, getcsvfield(tmp, 5));
strcat(f1, getcsvfield(tmp, 6));
strcat(a1, '\0');
strcat(b1, '\0');
strcat(c1, '\0');
strcat(d1, '\0');
strcat(e1, '\0');
strcat(f1, '\0');
// printf("Field 1 would be %s\n", a1);
// printf("Field 2 would be %s\n", getcsvfield(tmp, 2));
// printf("Field 2 would be %s\n", getcsvfield(tmp, 3));
// printf("Field 2 would be %s\n", getcsvfield(tmp, 4));
// printf("Field 2 would be %s\n", getcsvfield(tmp, 5));
// printf("Field 2 would be %s\n", getcsvfield(tmp, 6));
//--- // execute("INSERT INTO sdata(sid,name,area,type,stbamount,pkgamount) VALUES('%s','%s','%s','%s','%s','%s');",a1,b1,c1,d1,e1,f1);
// NOTE strtok clobbers tmp
free(tmp);
}
}
//Used for parsing CSV
const char* getcsvfield(char* line, int num)
{
char buffer[1024]= {0};
strcpy(buffer, line);
const char* tok;
for (tok = strtok(buffer, ";");
tok && *tok;
tok = strtok(NULL, ";\n"))
{
if (!--num)
return tok;
}
return NULL;
}
This is the CSV
me;val1;val2;val3;val4;val5;
me;val1;val2;val3;val4;val5;
ERROR:
Segmentation fault (core dumped)
UPDATE:
database.c
#include "../include/header.h"
int Open_Database()
{
int rc=0;
rc = Initialize_db();
if(rc == 0)
{
printf("\nFailed to initialize db");
return FAILED;
}
printf("\n Database initialization success");
rc = open_sqlite("/mnt/jffs2/db2.db");
if(rc == 0)
{
printf("\n Failed to open db");
return FAILED;
}
else
printf("Database already exists\n");
printf("\n database opened\n");
return SUCCESS;
}
int Initialize_db()
{
char *database = "/mnt/jffs2/db2.db";
int rc=0, i=0;
struct stat buf;
i = stat(database, &buf );
if((i<0) || (buf.st_size == 0))
{
printf("Initializing database...\n");
lk_dispclr();
lk_disptext(2,0,(unsigned char *)" Initializing DB...",0);
rc = open_sqlite(database);
if(rc == 0)
{
printf("Create database failure!\n");
lk_dispclr();
//DispText(2,0," Failed to Create",0);
//DispText(4,4," Database",0);
lk_getkey();
return FAILED;
}
else
{
rc = execute("CREATE TABLE if not exists sdata(sid VARCHAR(10),name VARCHAR(20),area VARCHAR(10),type VARCHAR(10),stbamount VARCHAR(10),pkgamount VARCHAR(10))");
if(rc==0)
{
return error_handler(rc);
}
else
{
printf("\n Master table created\n");
}
rc = execute("CREATE TABLE if not exists tdata(sid VARCHAR(10),stbamount VARCHAR(10),pkgamount VARCHAR(10))");
if(rc==0)
{
return error_handler(rc);
}
else
{
printf("\n Transaction table created\n");
}
}
close_sqlite();
}
else
{
printf("database already existed\n");
rc=1;
}
return rc;
}
int error_handler(int rc)
{
if(rc == 0)
{
printf("\n SQL Error while initializing!!!\n");
/*lk_dispclr();
DispText(2,0," SQL ERROR",0);
lk_getkey();
*/
return FAILED;
}
else
{
printf("SQL Successfull\n");
/*lk_dispclr();
DispText(2,0," SQL Successfull",0);
lk_getkey();*/
}
return SUCCESS;
}
//-----------------------------------------------------------------------
e_sqlite.c
#include "../include/sqlite3.h"
#include "../include/header.h"
#define ELEMENT_NUM(_array) ( sizeof(_array)/sizeof(_array[0]) )
sqlite3 *db_conn;
int ret = 0;
char OPEN_FLAG = 0;
int open_sqlite(char *db_name)
{
if(OPEN_FLAG == 0)
{
if(sqlite3_open(db_name, &db_conn) == SQLITE_OK)
{
OPEN_FLAG = 1;
printf("\nOPEN_FALG = %d\n",OPEN_FLAG);
printf("database opened\n");
return 1;
}
else
{
printf("database opening failed\n");
return 0;
}
}
else
{
printf("\ndatabase already opened\n");
return 1;
}
return 1;
}
int close_sqlite()
{
if(OPEN_FLAG == 1)
{
if(sqlite3_close(db_conn) == SQLITE_OK)
{
printf("database closed\n");
OPEN_FLAG = 0;
printf("OPEN_FLAG = %d\n",OPEN_FLAG);
return 1;
}
else
{
printf("database closing failed\n");
return 0;
}
}
else
{
printf("database not yet opened\n");
return 1;
}
}
//only type s and d are allowed as arguments
int execute(const char* fmt, ...)
{
char *err_messg;
int ret=0, result = 0;
char sql_string[2000]="";//this honestly needs to be more elegant; will do for now
//char sql_string[1024]="";//this honestly needs to be more elegant; will do for now
va_list args;
va_start(args, fmt);
SQLITE = 1;
memset(sql_string,0,sizeof(sql_string));
sql_string[0] = '\0';
ret = vsprintf(sql_string, fmt, args);
va_end(args);
err_printf(sql_string);//
if(!ret)
result = 0;
else
result = 1;
if(result != -1)
{
if(sqlite3_exec(db_conn, sql_string, NULL, 0, &err_messg) == SQLITE_OK)
{
result = 1;
}
else
{
fprintf(stdout,"SQL error: %s\n", err_messg);
result = 0;
}
}
SQLITE = 0;
return result;
}
//you must open_sqlite first before using execute_file
int execute_file(char *filename)
{
char *err_messg;
FILE *read_fd = (FILE *) 0;
char sql_string[1024];
ret = 0;
read_fd = fopen (filename, "r");//open file for read
if (read_fd != NULL)
{
rewind(read_fd);
while(!feof (read_fd))
{
m_fgets(sql_string, 1024, read_fd);
//ie if string is not empty, then execute - ha no more newline errors!
if(strcmp(sql_string, "") != 0)
{
//err_printf("SQL_STRING: %s\n", sql_string);
if(sqlite3_exec(db_conn, sql_string, NULL, 0, &err_messg) == SQLITE_OK)
{
ret = 1;
continue;
}
else
{
fprintf(stdout,"SQL error: %s\n", err_messg);
ret = 0;
break;
}
}
}
}
fclose(read_fd);
return ret;
}
char *m_fgets(char *line, int n, FILE *fd)
{
int c = 0;
char *cstring;
cstring = line;
while(--n>0 && ( c = getc(fd) ) != EOF)
{
if (c == '\n')
break;
*cstring++ = c;
}
*cstring++ = '\0';
if (c == EOF && cstring == line)//ie nothing in file!
line = NULL;
if (c == EOF)
line = NULL;
return line;
}
resultset get_result(const char* fmt, ...)
{
int success = 0;
int nrow=0, ncol=0, i=0, j=0, count=0;
char *err_messg;
char **result;
char ***recordset;
resultset resultset_table;
char sql_string[1500];//this honestly needs to be more elegant; will do for now
va_list args;
va_start(args, fmt);
sql_string[0] = '\0';
ret = vsprintf(sql_string, fmt, args);
va_end(args);
fprintf(stdout,"\n%s\n", sql_string);
SQLITE = 1;
//initialize resultset_table;
resultset_table.rows = 0;
resultset_table.cols = 0;
resultset_table.recordset = NULL;
ret = sqlite3_get_table(
db_conn,
sql_string,
&result,
&nrow,
&ncol,
&err_messg
);
fprintf(stdout,"nrow=%d ncol=%d\n",nrow,ncol);
recordset = (char ***)malloc(nrow * sizeof(char **));
for(count=ncol; count<((nrow + 1)*ncol); count++)
{
recordset[i] = (char **)malloc(ncol * sizeof(char *));
for(j=0; j<ncol; j++)
{
err_printf("%s ",result[count]);//
recordset[i][j] = (char *) malloc( (strlen(result[count]) + 1) );
strcpy(recordset[i][j], result[count]);
if(j != (ncol - 1))
count++;
}
i++;
err_printf("\n");//
}
sqlite3_free_table(result);
if( ret != SQLITE_OK )
{
fprintf(stdout,"SQL error: %s\n", err_messg);
success = 0;
}
else
{
resultset_table.rows = nrow;
resultset_table.cols = ncol;
resultset_table.recordset = recordset;
success = 1;
}
SQLITE = 0;
return resultset_table;
}
//will free all allocd memory ie only recordset memory (since only that allocd)
void free_result(resultset resultset_table)
{
int i=0,j=0;
if(resultset_table.recordset != NULL)
{
for(i=0;i<resultset_table.rows;i++)
{
for(j=0;j<resultset_table.cols;j++)
{
free(resultset_table.recordset[i][j]);
}
free(resultset_table.recordset[i]);
}
free(resultset_table.recordset);
}
}
//if DEBUG is on then print message to stderr using fprintf function
/*int err_printf(const char *fmt, ...)
{
int i;
va_list ap;
va_start(ap, fmt);
i = vfprintf(stderr, fmt, ap);
va_end(ap);
return i;
}*/
//returns the row index in the resultset that was selected
//column is the column of the resultset that you want to display
int err_printf(const char *fmt, ...)
{
int i;
// #ifdef DEBUG
va_list ap;
va_start(ap, fmt);
i = vfprintf(stderr, fmt, ap);
va_end(ap);
// #endif
return i;
}
Update:
Fix for Null Values:
I need to create RASENTRY for L2TP with pre-shared key set. So far, I can see that entry has somewhat correct flags, but no key is set, unfortunately.
Here is code:
int common_ras_manager_create_entry(const char* server_address, const char* username, const char* password, MY_VPN_CONNECTION_TYPE connection_type, const char* preshared_key)
{
DWORD EntryInfoSize = 0;
DWORD DeviceInfoSize = 0;
DWORD Ret;
LPRASENTRY lpRasEntry;
LPBYTE lpDeviceInfo;
// Get buffer sizing information for a default phonebook entry
if ((Ret = RasGetEntryProperties(NULL, "", NULL, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
if (Ret != ERROR_BUFFER_TOO_SMALL)
{
printf("RasGetEntryProperties sizing failed with error %d\n", Ret);
return Ret;
}
}
lpRasEntry = (LPRASENTRY) GlobalAlloc(GPTR, EntryInfoSize);
if (DeviceInfoSize == 0)
lpDeviceInfo = NULL;
else
lpDeviceInfo = (LPBYTE) GlobalAlloc(GPTR, DeviceInfoSize);
// Get default phonebook entry
lpRasEntry->dwSize = sizeof(RASENTRY);
if ((Ret = RasGetEntryProperties(NULL, "", lpRasEntry, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
printf("RasGetEntryProperties failed with error %d\n", Ret);
return Ret;
}
// Validate new phonebook name "Testentry"
if ((Ret = RasValidateEntryName(NULL, APP_NAME)) != ERROR_SUCCESS)
{
printf("RasValidateEntryName failed with error %d\n", Ret);
if (Ret != ERROR_ALREADY_EXISTS)
return Ret;
}
LPRASDEVINFO ras_devices;
DWORD cb =sizeof(RASDEVINFO);
DWORD cbDevices = 0;
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
if ((Ret = RasEnumDevices(ras_devices, &cb, &cbDevices)) != ERROR_SUCCESS)
{
printf("RasEnumDevices failed with error %d\n", Ret);
switch(Ret)
{
case ERROR_BUFFER_TOO_SMALL:
printf("buffer too small");
HeapFree(GetProcessHeap(), 0, (LPVOID)ras_devices);
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
Ret = RasEnumDevices(ras_devices, &cb, &cbDevices);
if (ERROR_SUCCESS == Ret)
{
//fSuccess = TRUE;
}
else
{
printf("RasEnumDevices failed again: Error = %d\n", Ret);
return Ret;
//goto done;
}
break;
case ERROR_NOT_ENOUGH_MEMORY:
printf("ERROR_NOT_ENOUGH_MEMORY");
return Ret;
break;
case ERROR_INVALID_PARAMETER:
printf("ERROR_INVALID_PARAMETER");
return Ret;
break;
case ERROR_INVALID_USER_BUFFER:
printf("ERROR_INVALID_USER_BUFFER");
return Ret;
break;
}
}
DWORD dwVpnStrategy = 0;
char device_name_mask[5];
strcpy(device_name_mask, "");
gboolean preshared_key_valid = 0;
switch(connection_type)
{
case PPTP:
strcpy(device_name_mask, "PPTP");
dwVpnStrategy = VS_PptpOnly;
break;
case L2TP:
if (preshared_key == 0 || strlen(preshared_key) == 0)
{
printf("CRITICAL: preshared key not set.");
return 1;
}
else
{
preshared_key_valid = TRUE;
}
strcpy(device_name_mask, "L2TP");
dwVpnStrategy = VS_L2tpOnly;
break;
}
int i =0;
for (i = 0; i < cbDevices; i++)
{
RASDEVINFO r = ras_devices[i];
if (strstr(r.szDeviceName, device_name_mask))
{
break;
}
}
//lpRasEntry->dwfOptions |= RASEO_SpecificIpAddr;
//lpRasEntry->szLocalPhoneNumber = RASDT_Vpn;
lpRasEntry->dwfNetProtocols |= RASNP_Ip;
lpRasEntry->dwFramingProtocol = RASFP_Ppp;
lstrcpy(lpRasEntry->szDeviceType, RASDT_Vpn);
lstrcpy(lpRasEntry->szDeviceName, ras_devices[i].szDeviceName);
lstrcpy(lpRasEntry->szLocalPhoneNumber, server_address);
lpRasEntry->dwVpnStrategy = dwVpnStrategy; // VS_PptpOnly; VS_SstpOnly
if (preshared_key_valid)
{
L2TP_CONFIG_DATA* data = GlobalAlloc(GPTR, sizeof(L2TP_CONFIG_DATA));
lpRasEntry->dwfOptions2 |= RASEO2_UsePreSharedKey;
data->dwOffsetKey = 16;
memcpy((PBYTE)data + data->dwOffsetKey, preshared_key, strlen(preshared_key));
data->dwAuthType =L2TP_IPSEC_AUTH_PRESHAREDKEY;
RasSetCustomAuthData(NULL, APP_NAME, data, sizeof(L2TP_CONFIG_DATA));
}
if ((Ret = RasSetEntryProperties(NULL, APP_NAME, lpRasEntry, EntryInfoSize, lpDeviceInfo, DeviceInfoSize)) != 0)
{
printf("RasSetEntryProperties failed with error %d\n", Ret);
return Ret;
}
//if ((Ret = RasSetCredentials(NULL, lpRasEntry.))
}
I cant find where is buffer to fill for pre-shared key.
Following code works fine.
// l2tp
if (preshared_key_valid)
{
RASCREDENTIALS ras_cre_psk = {0};
ras_cre_psk.dwSize = sizeof(ras_cre_psk);
ras_cre_psk.dwMask = 0x00000010; //RASCM_PreSharedKey;
wcscpy(ras_cre_psk.szPassword, preshared_key);
if ((Ret = RasSetCredentials(NULL, APP_NAME, &ras_cre_psk, FALSE)))
{
printf("RasSetCredentials failed with error %d\n", Ret);
return Ret;
}
}
I was using OpenSSL version 0.9.8h in an Android project. I update it to the 0.9.8.zf version but now it doesn't work.
The two functions that highlight the problem are initialize_client_ctx and initialize_client_ctx. When I call SSL_connect I get an SSL_ERROR_SSL error value. By checking details I retrieve a "bad packet length" error (error:14092073:SSL routines:SSL3_GET_SERVER_HELLO:bad packet length).
The point in the code is indicated in a comment. The code works well with the previous version. I attach also a Wireshark capture file. Any ideas?
SSL_CTX *initialize_client_ctx(const char *keyfile, const char *certfile,
const char *password, int transport)
{
SSL_METHOD *meth = NULL;
X509 *cert = NULL;
SSL_CTX *ctx;
if (transport == IPPROTO_UDP) {
meth = DTLSv1_client_method();
} else if (transport == IPPROTO_TCP) {
meth = TLSv1_client_method();
} else {
return NULL;
}
ctx = SSL_CTX_new(meth);
if (ctx == NULL) {
//print ... Couldn't create SSL_CTX
return NULL;
}
if (password[0] != '\0') {
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) password);
SSL_CTX_set_default_passwd_cb(ctx, password_cb);
}
if (tls_client_local_cn_name[0] != '\0') {
cert = _tls_set_certificate(ctx, tls_client_local_cn_name);
}
if (cert==NULL && certfile[0] != '\0') {
//print several warnings....
}
if (cert!=NULL)
{
X509_free(cert);
cert = NULL;
}
/* Load the CAs we trust */
{
char *caFile = 0, *caFolder = 0;
int fd = open(eXosip_tls_ctx_params.root_ca_cert, O_RDONLY);
if (fd >= 0) {
struct stat fileStat;
if (fstat(fd, &fileStat) < 0) {
} else {
if (S_ISDIR(fileStat.st_mode)) {
caFolder = eXosip_tls_ctx_params.root_ca_cert;
} else {
caFile = eXosip_tls_ctx_params.root_ca_cert;
}
}
close(fd);
}
{
int verify_mode = SSL_VERIFY_PEER;
SSL_CTX_set_verify(ctx, verify_mode, &verify_cb);
SSL_CTX_set_verify_depth(ctx, ex_verify_depth + 1);
}
}
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
SSL_OP_CIPHER_SERVER_PREFERENCE);
if(!SSL_CTX_set_cipher_list(ctx,"ALL")) {
//print ... set_cipher_list: cannot set anonymous DH cipher
SSL_CTX_free(ctx);
return NULL;
}
return ctx;
}
static int _tls_tl_ssl_connect_socket(struct socket_tab *sockinfo)
{
X509 *cert;
BIO *sbio;
int res;
if (sockinfo->ssl_ctx == NULL) {
sockinfo->ssl_ctx =
initialize_client_ctx(eXosip_tls_ctx_params.client.priv_key,
eXosip_tls_ctx_params.client.cert,
eXosip_tls_ctx_params.client.priv_key_pw,
IPPROTO_TCP);
sockinfo->ssl_conn = SSL_new(sockinfo->ssl_ctx);
if (sockinfo->ssl_conn == NULL) {
return -1;
}
sbio = BIO_new_socket(sockinfo->socket, BIO_NOCLOSE);
if (sbio == NULL) {
return -1;
}
SSL_set_bio(sockinfo->ssl_conn, sbio, sbio);
}
do {
struct timeval tv;
int fd;
fd_set readfds;
res = SSL_connect(sockinfo->ssl_conn);
res = SSL_get_error(sockinfo->ssl_conn, res);
if (res == SSL_ERROR_NONE) {
//printf... SSL_connect succeeded
break;
}
if (res != SSL_ERROR_WANT_READ && res != SSL_ERROR_WANT_WRITE) {
//<-- here there is a problem res == SSL_ERROR_SSL
//print ERR_reason_error_string(ERR_get_error()));
//print ERR_error_string(ERR_get_error(), NULL));
return -1;
}
tv.tv_sec = SOCKET_TIMEOUT / 1000;
tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
//retry the connection
fd = SSL_get_fd(sockinfo->ssl_conn);
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
res = select(fd + 1, &readfds, NULL, NULL, &tv);
if (res < 0) {
//print error
return -1;
} else if (res > 0) {
//print...connetrion done!
} else {
//socket timeout, no data to read
return 1;
}
} while (!SSL_is_init_finished(sockinfo->ssl_conn));
if (SSL_is_init_finished(sockinfo->ssl_conn)) {
//print.. SSL_is_init_finished done
} else {
//print.. failed
}
cert = SSL_get_peer_certificate(sockinfo->ssl_conn);
if (cert != 0) {
int cert_err;
tls_dump_cert_info("tls_connect: remote certificate: ", cert);
cert_err = SSL_get_verify_result(sockinfo->ssl_conn);
if (cert_err != X509_V_OK) {
//print... Failed to verify remote certificate
tls_dump_verification_failure(cert_err);
if (eXosip_tls_ctx_params.server.cert[0] != '\0') {
X509_free(cert);
return -1;
} else if (cert_err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
&& cert_err != X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
&& cert_err != X509_V_ERR_CRL_HAS_EXPIRED
&& cert_err != X509_V_ERR_CERT_HAS_EXPIRED
&& cert_err != X509_V_ERR_CERT_REVOKED
&& cert_err != X509_V_ERR_CERT_UNTRUSTED
&& cert_err != X509_V_ERR_CERT_REJECTED) {
X509_free(cert);
return -1;
}
}
X509_free(cert);
} else {
//print .. No certificate received
/* X509_free is not necessary because no cert-object was created -> cert == NULL */
if (eXosip_tls_ctx_params.server.cert[0] == '\0') {
#ifdef ENABLE_ADH
/* how can we guess a user want ADH... specific APIs.. */
sockinfo->ssl_state = 3;
return 0;
#endif
}
return -1;
}
sockinfo->ssl_state = 3;
return 0;
}
SOLVED Thanks to Eric Tsui that helps me to figure out the problem. The 'hello' that I receive from the server in the handshake has zero length. To solve this I modified the file openssl/ssl/s3_clnt.c in the following way (toggling off the length control):
diff -ur ./s3_clnt.c ./original/s3_clnt.c
--- submodules/externals/openssl/ssl/s3_clnt.c 2015-06-29 14:59:56.723462992 +0200
+++ ../../opensslOrig/s3_clnt.c 2015-06-29 15:00:22.487464221 +0200
## -868,12 +868,14 ##
}
#endif
+#ifndef OPENSSL_NO_TLSEXT
if (p != (d + n)) {
/* wrong packet length */
al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH);
goto f_err;
}
+#endif
return (1);
f_err:
I have a buffer overflow vulnerability in a simple webserver. It can be exploited with a http GET request. I'm having trouble figuring out how to fix it. My guess is that it has to do with: char hdrval[1024]; but I could be wrong. Can anyone else see whats wrong?
Code:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>
#define _XOPEN_SOURCE
typedef struct {
char *method;
char *uri;
char *version;
char *headers;
} httpreq_t;
/* NOTE: this function is based on a function provided in the GNU "timegm" man
page. timegm is a GNU extension to time.h that returns the given tm struct as
a UNIX timestamp in GMT/UTC, rather than local time. The man page suggests a
function similar to the one below as a portable equivalent.
*/
time_t my_timegm(struct tm *tm) {
time_t ret;
char *tz;
tz = getenv("TZ");
putenv("TZ=GMT");
tzset();
ret = mktime(tm);
if (tz) {
char envstr[strlen(tz) + 4];
envstr[0] = '\0';
strcat(envstr, "TZ=");
strcat(envstr, tz);
putenv(envstr);
} else {
putenv("TZ=");
}
tzset();
return ret;
}
char *get_header(const httpreq_t *req, const char* headername) {
char *hdrptr;
char *hdrend;
char *retval = NULL;
char searchstr[strlen(headername) + 5];
strcpy(searchstr, "\r\n");
strcat(searchstr, headername);
strcat(searchstr, ": ");
if (hdrptr = strstr(req->headers, searchstr)) {
hdrptr += strlen(searchstr);
if (hdrend = strstr(hdrptr, "\r\n")) {
char hdrval[1024]; // temporary return value
memcpy((char *)hdrval, hdrptr, (hdrend - hdrptr));
hdrval[hdrend - hdrptr] = '\0'; // tack null onto end of header value
int hdrvallen = strlen(hdrval);
retval = (char *)malloc((hdrvallen + 1) * sizeof(char)); // malloc a space for retval
strcpy(retval, (char *)hdrval);
} else {
retval = (char *)malloc((strlen(hdrptr) + 1) * sizeof(char)); //
strcpy(retval, hdrptr);
}
}
return retval;
}
/* As long as str begins with a proper HTTP-Version followed by delim, returns a
pointer to the start of the version number (e.g., 1.0). Returns NULL otherwise.
*/
char *http_version_str(char *str, char *delim) {
char *vstart = strstr(str, "HTTP/");
char *vnumstart = str + 5;
char *vdot = strchr(str, '.');
char *vend = strstr(str, delim);
char *digits = "0123456789";
int majvlen = 0;
int minvlen = 0;
if (!vstart || !vdot // something's missing
|| vstart != str) // str doesn't start with "HTTP/"
return NULL;
majvlen = strspn(vnumstart, digits);
minvlen = strspn(vdot + 1, digits);
if (majvlen < 1 || (vnumstart + majvlen) != vdot // bad major version
|| minvlen < 1 || (vdot + minvlen + 1) != vend) // bad minor version
return NULL;
return vnumstart;
}
/* Fills req with the request data from datastr. Returns 0 on success.
*/
int parsereq(httpreq_t *req, char *datastr) {
char *position;
char *last_position = datastr;
char *temp_position;
int matchlen;
req->method = "";
req->uri = "";
req->version = "";
req->headers = "";
if (!(position = strchr(last_position, ' '))) {
return 1;
}
matchlen = (int)(position - last_position);
req->method = (char *)malloc((matchlen + 1) * sizeof(char));
memcpy(req->method, last_position, matchlen);
req->method[matchlen] = '\0';
last_position = position + 1;
if (!(position = strchr(last_position, ' '))
&& !(position = strstr(last_position, "\r\n"))) {
return 1;
}
// strip any query string out of the URI
if ((temp_position = strchr(last_position, '?')) && temp_position < position)
matchlen = (int)(temp_position - last_position);
else
matchlen = (int)(position - last_position);
req->uri = (char *)malloc((matchlen + 1) * sizeof(char));
memcpy(req->uri, last_position, matchlen);
req->uri[matchlen] = '\0';
if (position[0] == '\r') {
req->version = "0.9";
req->headers = "";
return 0; // simple req -- uri only
}
// If we get here, it's a full request, get the HTTP version and headers
last_position = position + 1;
if (!(position = strstr(last_position, "\r\n"))
|| !(last_position = http_version_str(last_position, "\r\n"))) {
return 1;
}
matchlen = (int)(position - last_position);
req->version = (char *)malloc((matchlen + 1) * sizeof(char));
memcpy(req->version, last_position, matchlen);
req->version[matchlen] = '\0';
last_position = position;
req->headers = (char *)malloc(strlen(last_position) * sizeof(char));
strcpy(req->headers, last_position);
return 0;
}
char *contype(char *ext) {
if (strcmp(ext, "html") == 0) return "text/html";
else if (strcmp(ext, "htm") == 0) return "text/html";
else if (strcmp(ext, "jpeg") == 0) return "image/jpeg";
else if (strcmp(ext, "jpg") == 0) return "image/jpeg";
else if (strcmp(ext, "gif") == 0) return "image/gif";
else if (strcmp(ext, "txt") == 0) return "text/plain";
else return "application/octet-stream";
}
char *status(int statcode) {
if (statcode == 200) return "200 OK";
else if (statcode == 304) return "304 Not Modified";
else if (statcode == 400) return "400 Bad Request";
else if (statcode == 403) return "403 Forbidden";
else if (statcode == 404) return "404 Not Found";
else if (statcode == 500) return "500 Internal Server Error";
else if (statcode == 501) return "501 Not Implemented";
else return "";
}
int send_response(int sockfd, httpreq_t *req, int statcode) {
int urifd;
const int BUFSIZE = 1024;
char sendmessage[BUFSIZE];
char *path = req->uri;
if (req->uri == NULL || req->method == NULL ||
req->headers == NULL || req->version == NULL) {
return 0;
}
if ((path[0] == '/') || ((strstr(path, "http://") == path)
&& (path = strchr(path + 7, '/')))) {
path += 1; // remove leading slash
if (path[0] == '\0') { // substituting in index.html for a blank URL!
path = "index.html";
} else if (path[strlen(path) - 1] == '/') {
//concatenating index.html for a /-terminated URL!
strcat(path, "index.html");
}
} else {
statcode = 400;
}
if (statcode == 200 && (urifd = open(path, O_RDONLY, 0)) < 0) {
if (errno == ENOENT || errno == ENOTDIR) { // file or directory doesn't exist
statcode = 404;
} else if (errno == EACCES) { // access denied
statcode = 403;
} else {
// some other file access problem
statcode = 500;
}
}
if (strstr(path, "..") != NULL) {
statcode = 500;
}
sendmessage[0] = '\0';
if (strcmp(req->version, "0.9") != 0) { // full request
char *ext; // file extension
time_t curtime;
char *imstime;
struct tm tm;
struct stat stbuf;
if (statcode == 200) {
if (ext = strrchr(path, '.')) ext++; // skip the '.'
else ext = "";
} else {
// errors are always html messages
ext = "html";
}
// Conditional GET
if ((strcmp(req->method, "GET") == 0)
&& (statcode == 200)
&& (imstime = get_header(req, "If-Modified-Since"))) {
// Get statistics about the requested URI from the local filesystem
if (stat(path, &stbuf) == -1) {
statcode = 500;
}
if (!strptime(imstime, "%a, %d %b %Y %H:%M:%S GMT", &tm)
&& !strptime(imstime, "%a, %d-%b-%y %H:%M:%S GMT", &tm)
&& !strptime(imstime, "%a %b %d %H:%M:%S %Y", &tm)) {
// badly formatted date
statcode = 400;
}
if (stbuf.st_mtime <= my_timegm(&tm)) {
// Not Modified
statcode = 304;
}
}
time(&curtime); // time for Date: header
strcat(sendmessage, "HTTP/1.0 ");
strcat(sendmessage, status(statcode));
strcat(sendmessage, "\r\nDate: ");
strncat(sendmessage, asctime(gmtime(&curtime)), 24);
strcat(sendmessage, "\r\nServer: Frobozz Magic Software Company Webserver v.002");
strcat(sendmessage, "\r\nConnection: close");
strcat(sendmessage, "\r\nContent-Type: ");
strcat(sendmessage, contype(ext));
strcat(sendmessage, "\r\n\r\n");
}
if (statcode != 200) {
strcat(sendmessage, "<html><head><title>");
strcat(sendmessage, status(statcode));
strcat(sendmessage, "</title></head><body><h2>HTTP/1.0</h2><h1>");
strcat(sendmessage, status(statcode));
strcat(sendmessage, "</h1><h2>URI: ");
strcat(sendmessage, path);
strcat(sendmessage, "</h2></body></html>");
}
if (sendmessage[0] != '\0') {
// send headers as long as there are headers to send
if (send(sockfd, sendmessage, strlen(sendmessage), 0) < 0) {
perror("send");
pthread_exit(NULL);
}
}
if (statcode == 200 && (strcmp(req->method, "HEAD") != 0)) {
// send the requested file as long as there's no error and the
// request wasn't just for the headers
int readbytes;
while (readbytes = read(urifd, sendmessage, BUFSIZE)) {
if (readbytes < 0) {
perror("read");
pthread_exit(NULL);
}
if (send(sockfd, sendmessage, readbytes, 0) < 0) {
perror("send");
pthread_exit(NULL);
}
}
}
}
void *data_thread(void *sockfd_ptr) {
int sockfd = *(int *) sockfd_ptr;
const int BUFSIZE = 5;
char recvmessage[BUFSIZE];
char *headerstr = NULL;
char *newheaderstr = NULL;
int recvbytes = 0;
int curheadlen = 0;
int totalheadlen = 0;
httpreq_t req;
int statcode = 200;
int done = 0;
int seen_header = 0;
char *header_end;
int content_length = 0;
char *qstr;
free(sockfd_ptr); // we have the int value out of this now
recvmessage[BUFSIZE - 1] = '\0'; // mark end of "string"
/* Read incoming client message from the socket */
while(!done && (recvbytes = recv(sockfd, recvmessage, BUFSIZE - 1, 0))) {
if (recvbytes < 0) {
perror("recv");
pthread_exit(NULL);
}
recvmessage[recvbytes] = '\0';
if (seen_header) {
// getting the entity body
content_length -= recvbytes;
if (content_length <= 0) done = 1;
} else {
newheaderstr = (char *) malloc((totalheadlen + recvbytes + 1) * sizeof(char));
newheaderstr[totalheadlen + recvbytes] = '\0';
memcpy(newheaderstr, headerstr, totalheadlen);
memcpy(newheaderstr + totalheadlen, recvmessage, recvbytes);
if (headerstr) free(headerstr);
headerstr = newheaderstr;
totalheadlen += recvbytes;
header_end = strstr(headerstr, "\r\n\r\n");
if (header_end) {
seen_header = 1;
header_end[2] = '\0';
if (parsereq(&req, headerstr) != 0) {
statcode = 400;
}
if (strcmp(req.method, "POST") == 0) {
// grab the body length
char *clenstr = get_header(&req, "Content-Length");
if (clenstr) {
content_length = atoi(clenstr) - ((headerstr + totalheadlen) - header_end - 4);
if (content_length <= 0) done = 1;
free(clenstr);
} else {
statcode = 400; // bad request -- no content length
done = 1;
}
} else {
// This isn't a POST, so there's no entity body
done = 1;
if (strcmp(req.method, "GET") != 0
&& strcmp(req.method, "HEAD") != 0) {
statcode = 501; // unknown request method
}
}
}
}
} // end of recv while loop
// used to deref a NULL pointer here... :(
if (headerstr != NULL) {
printf("%s\n", headerstr);
free(headerstr);
}
send_response(sockfd, &req, statcode);
close(sockfd);
return NULL;
}
int main(int argc, char *argv[]) {
int acc, sockfd, clen, port;
struct hostent *he;
struct sockaddr_in caddr, saddr;
if(argc <= 1) {
fprintf(stderr, "No port specified. Exiting!\n");
exit(1);
}
port = atoi(argv[1]);
/* Obtain name and address for the local host */
if((he=gethostbyname("localhost"))==NULL) {
herror("gethostbyname");
exit(1);
}
/* Open a TCP (Internet Stream) socket */
if((sockfd=socket(AF_INET,SOCK_STREAM,0)) == -1) {
perror("socket");
exit(1);
}
/* Create socket address structure for the local host */
memset((char *) &saddr, '\0', sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(port);
saddr.sin_addr.s_addr=htonl(INADDR_ANY);
/* Bind our local address so that the client can send to us */
if(bind(sockfd,(struct sockaddr *) &saddr,sizeof(saddr)) == -1) {
perror("bind");
exit(1);
}
if(listen(sockfd,5) < 0) {
perror("listen");
exit(1);
}
/* Infinite loop for receiving and processing client requests */
for(;;) {
clen=sizeof(caddr);
/* Wait for a connection for a client process */
acc=accept(sockfd,(struct sockaddr *) &caddr,(socklen_t*)&clen);
if(acc < 0) {
perror("accept");
exit(1);
} else {
pthread_t *thread = (pthread_t *) malloc(sizeof(pthread_t));
int *sockfd_ptr = (int *) malloc(sizeof(int));
*sockfd_ptr = acc;
pthread_create(thread, NULL, data_thread, sockfd_ptr);
}
}
return 0;
}
I guess you could have a bound check before copying to the buffer?
For example, add
if(hdrend - hdrptr >= 1024)
exit(1)
before
memcpy((char *)hdrval, hdrptr, (hdrend - hdrptr));
The segfault happens at the point below.
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7ff4b70 (LWP 3902)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7ff4b70 (LWP 3902)]
0x08049507 in send_response (sockfd=6, req=0xb7ff4340, statcode=200)
at server/webserver.c:219
warning: Source file is more recent than executable.
219 if (req->uri == NULL || req->method == NULL ||
The memory address is
(gdb) p $_siginfo._sifields._sigfault.si_addr
$3 = (void *) 0x69cb120
The code that needs to be rewritten is
214 int urifd;
215 const int BUFSIZE = 1024;
216 char sendmessage[BUFSIZE];
217 char *path = req->uri;
218
219 if (req->uri == NULL || req->method == NULL ||
220 req->headers == NULL || req->version == NULL) {
221 return 0;