summaryrefslogblamecommitdiffstats
path: root/core/modules/pam/sslconnect.c
blob: af43093c7084aa7a57af2e863b25327ed5a88e5b (plain) (tree)








































































































































































































                                                                                                                 
/************************
 * sslconnect 0.2
 * Last Change: 2013-06-17
 * C Implementation by Simon Rettberg
 * Original sslconnect 0.1 was written in perl by Martin Walter
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

/* Init libs and data strctures */
void init();
/* print error report of something failed */
void ssl_error();
/* connect via ssl */
SSL* ssl_connect(char * host, uint16_t port, uint16_t local_port, SSL_CTX ** ctx);
/* read from ssl connection */
ssize_t ssl_read(SSL * bio, char * buffer, ssize_t length);
/* write to ssl connection */
int ssl_write(SSL * bio, char * buffer, ssize_t length);

int main(int argc, char ** argv);

void init()
{
	SSL_load_error_strings();
	SSL_library_init();
	OpenSSL_add_all_algorithms();
}

void ssl_error(char* message)
{
	fprintf(stderr, message);
	fprintf(stderr, "\n%s\n", ERR_error_string(ERR_get_error(), NULL));
	fprintf(stderr, "Details: %s\n", ERR_reason_error_string(ERR_get_error()));
	ERR_print_errors_fp(stderr);
}

SSL* ssl_connect(char * host, uint16_t port, uint16_t local_port, SSL_CTX ** ctx)
{
	int ret = 0;
	/* create socket. needs to be done manually in order to bind to local port */
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if (fd < 0) {
		fprintf(stderr, "Could not create socket.\n");
		return NULL;
	}

	struct sockaddr_in sa_dest, sa_local;
	memset(&sa_local, 0, sizeof(sa_local));
	memset(&sa_dest, 0, sizeof(sa_dest));

	sa_local.sin_family = AF_INET;
	sa_local.sin_port = htons(local_port);
	ret = bind(fd, (struct sockaddr *)&sa_local, sizeof(struct sockaddr));
	if (ret == -1) {
		fprintf(stderr, "Could not bind local socket to 0.0.0.0:%d (%d)\n", (int)local_port, (int)errno);
		close(fd);
		return NULL;
	}

	sa_dest.sin_family = AF_INET;
	sa_dest.sin_port = htons(port);
	struct hostent * rec;
	rec = gethostbyname(host);
	if (rec == NULL) {
		fprintf(stderr, "Error: Invalid host: %s\n", host);
		return NULL;
	}
	memcpy(&(sa_dest.sin_addr), rec->h_addr, sizeof(struct in_addr));

	ret = connect(fd, (struct sockaddr *)&sa_dest, sizeof(struct sockaddr));
	if (ret == -1) {
		fprintf(stderr, "Could not connect to %s:%d (%d)\n", host, (int)port, (int)errno);
		close(fd);
		return NULL;
	}

	/* openssl part */
	SSL * ssl;

	/* Set up the SSL pointers */
	*ctx = SSL_CTX_new(SSLv23_client_method());
	ssl = SSL_new(*ctx);
	SSL_set_fd(ssl, fd);
	ret = SSL_connect(ssl);

	if (ret <= 0) {
		ssl_error("Unable to SSL_connect");
		return NULL;
	}

	SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

	return ssl;
}

ssize_t ssl_read(SSL * ssl, char * buffer, ssize_t length)
{
	ssize_t ret = -1;
	int retries = 10;

	while (ret < 0 && --retries > 0) {

		ret = SSL_read(ssl, buffer, length);
		if (ret >= 0) {
			return ret;
		}

		ssl_error("SSL_read failed");
		return -1;

	}

	return -1;
}

int ssl_write(SSL * ssl, char * buffer, ssize_t length)
{
	ssize_t ret = -1;
	int retries = 10;

	while (ret < 0 && --retries > 0) {

		ret = SSL_write(ssl, buffer, length);
		if (ret >= 0) {
			return ret;
		}

		ssl_error("SSL_write failed");
		return -1;

	}

	return -1;
}

#define READBUF 5000
int main(int argc, char ** argv)
{
	if (argc < 2) {
		fprintf(stderr, "Usage: %s host:port\n", argv[0]);
		return 1;
	}

	init();

	char buffer[READBUF];
	SSL_CTX * ctx = NULL;
	SSL * ssl;
	ssize_t len;
	size_t ret;
	char * pos;
	int port, lport;
	pos = strchr(argv[1], ':');
	if (pos == NULL) {
		fprintf(stderr, "Error: No Port given.\n");
		return 5;
	}
	port = atoi(pos+1);
	*pos = '\0';

	lport = rand() % 800 + 95;

	ssl = ssl_connect(argv[1], (uint16_t)port, (uint16_t)lport, &ctx);
	if (ssl == NULL) {
		return 2;
	}

	ssl_write(ssl, "", 0);
	for (;;) {
		len = ssl_read(ssl, buffer, READBUF);
		if (len <= 0) {
			break;
		}
		ret = fwrite(buffer, 1, len, stdout);
		if (ret != len) {
			fprintf(stderr, "Error: fwrite could not write all received data to stdout.\n");
			return 3;
		}
	}

	if (len < 0) {
		return 4;
	}

	return 0;
}