[Help-gnutls] Equivalent to fdopen?
Brian Lavender
brian at brie.com
Sun Aug 3 23:11:52 CEST 2008
I am trying to take a simple socket program and convert it to use
gnutls. Is there an equivalent to fdopen so I can stream my secured
socket as an fstream?
int sock_fd;
FILE *sock_fpi;
sock_fd = accept( sock_id, (struct sockaddr *) &sa_cli, &client_len );
sock_fpi = fdopen( sock_fd, "r" ))
But when I attempt to convert it to use gnutls, I run into the
following.
sock_fd = accept( sock_id, (struct sockaddr *) &sa_cli, &client_len );
session = initialize_tls_session ();
gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sock_fd );
ret = gnutls_handshake (session);
And, it appears that I can only read using the following command.
ret = gnutls_record_recv (session, buffer, MAX_BUF);
Any sugguestions? Is there an fdopen equivalent, so I can still use the
fgets and friends? Or, do I have to write my own buffering routine?
brian
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>
#include <string.h>
#include <gnutls/gnutls.h>
#include <gcrypt.h> /* for gcry_control */
#define PORTNUM 15000
#define HOSTLEN 256
#define DH_BITS 2048
#define oops(msg) { perror(msg); exit(1); }
#define KEYFILE "key.pem"
#define CERTFILE "cert.pem"
#define CAFILE "ca.pem"
#define CRLFILE "crl.pem"
/* These are global */
gnutls_certificate_credentials_t x509_cred;
gnutls_priority_t priority_cache;
gnutls_session_t
initialize_tls_session (void)
{
gnutls_session_t session;
gnutls_init (&session, GNUTLS_SERVER);
gnutls_priority_set (session, priority_cache);
gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
/* request client certificate if any.
*/
gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
/* Set maximum compatibility mode. This is only suggested on public webservers
* that need to trade security for compatibility
*/
gnutls_session_enable_compatibility_mode( session);
return session;
}
static gnutls_dh_params_t dh_params;
static int
generate_dh_params (void)
{
/* Generate Diffie Hellman parameters - for use with DHE
* kx algorithms. When short bit length is used, it might
* be wise to regenerate parameters.
*
* Check the ex-serv-export.c example for using static
* parameters.
*/
gnutls_dh_params_init (&dh_params);
gnutls_dh_params_generate2 (dh_params, DH_BITS);
return 0;
}
int main(int ac, char *av[] )
{
int ret; // return value
struct sockaddr_in saddr;
struct sockaddr_in sa_cli;
int client_len;
struct hostent *hp;
char hostname[HOSTLEN];
int sock_id, sock_fd;
FILE *sock_fpi, *sock_fpo;
FILE *pipe_fp;
char topbuf[512];
char dirname[BUFSIZ];
char command[BUFSIZ];
int dirlen, c;
gnutls_session_t session;
/* to disallow usage of the blocking /dev/random
*/
/* gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);*/
/* this must be called once in the program
*/
gnutls_global_init ();
gnutls_certificate_allocate_credentials (&x509_cred);
gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE,
GNUTLS_X509_FMT_PEM);
gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE,
GNUTLS_X509_FMT_PEM);
gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE,
GNUTLS_X509_FMT_PEM);
generate_dh_params ();
gnutls_priority_init( &priority_cache, "NORMAL", NULL);
gnutls_certificate_set_dh_params (x509_cred, dh_params);
/* step 1 */
sock_id = socket( PF_INET, SOCK_STREAM, 0 );
if ( sock_id == -1 )
oops("socket");
/* step 2 */
bzero( (void *)&saddr, sizeof(saddr) );
gethostname( hostname, HOSTLEN );
hp = gethostbyname( hostname );
// bcopy( (void *)hp->h_addr, (void *)&saddr.sin_addr, hp->h_length);
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(PORTNUM);
saddr.sin_family = AF_INET;
if( bind(sock_id, (struct sockaddr *)&saddr, sizeof(saddr)) != 0 )
oops( "bind" );
/* step 3 */
if ( listen(sock_id, 1) != 0 )
oops("listen");
printf ("Server ready. Listening to port '%d'.\n\n", PORTNUM);
/* main loop: accept, write, close */
client_len = sizeof (sa_cli);
while(1)
{
session = initialize_tls_session ();
sock_fd = accept( sock_id, (struct sockaddr *) &sa_cli, &client_len );
if ( sock_fd == -1 )
oops("accept");
printf ("- connection from %s, port %d\n",
inet_ntop (AF_INET, &sa_cli.sin_addr, topbuf,
sizeof (topbuf)), ntohs (sa_cli.sin_port));
gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sock_fd );
ret = gnutls_handshake (session);
if (ret < 0)
{
close (sock_fd);
gnutls_deinit (session);
fprintf (stderr, "*** Handshake has failed (%s)\n\n",
gnutls_strerror (ret));
continue;
}
printf ("- Handshake was completed\n");
/* STOP here. PARE aca. :) Now we have a tls_session that
we read from. It's not
a file descriptor anymore. Can't use fdopen on session :( */
/* open reading direction as buffered stream */
if ( ( sock_fpi = fdopen( sock_fd, "r" )) == NULL )
oops("fdopen reading ");
if ( fgets( dirname, BUFSIZ - 5, sock_fpi) == NULL )
oops("reading dirname");
sanitize(dirname);
/* open writing direction as buffered stream */
if ( (sock_fpo = fdopen(sock_fd,"w")) == NULL )
oops("fdopen writing");
sprintf( command, "ls %s", dirname);
if ( (pipe_fp = popen(command, "r")) == NULL)
oops("popen");
/* transfer data from ls to socket */
while ( ( c = getc(pipe_fp)) != EOF )
putc( c , sock_fpo );
pclose(pipe_fp);
fclose(sock_fpo);
fclose(sock_fpi);
}
return 0;
}
sanitize( char *str )
{
char *src, *dest;
for( src = dest = str; *src; src++ )
if ( *src == '/' || isalnum(*src) )
*dest++ = *src;
*dest = '\0';
}
--
Brian Lavender
http://www.brie.com/brian/
More information about the Gnutls-help
mailing list