[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