*** /dev/null	Mon Oct  6 15:20:00 2003
--- stunnel-4.04/src/ldap.c	Wed Oct  1 20:50:56 2003
***************
*** 0 ****
--- 1,136 ----
+ #ifdef USE_DISPATCH
+ 
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <string.h>
+ #include <stdlib.h>
+ #include <lber.h>
+ #include <ldap.h>
+ #include <netdb.h>
+ 
+ #include "common.h"
+ #include "prototypes.h"
+ 
+ #define SEP             '@'             // Will be replaced by uid
+ #define YES             (1)
+ #define FAIL		(-1)
+ 
+ 
+ int dispatch(char *ldapurl, char *peerdn, char *taddr)
+ {
+ 	LDAP *ld;
+         int rc, n;
+         static char *filter;
+         LDAPMessage *e, *res = NULL;
+         char **vals;
+         char *bp, *tp;
+ 	LDAPURLDesc *lud;
+ 	int escapes = 0;
+ 	char *escapeddn;
+ 
+ 	if (ldap_url_parse(ldapurl, &lud) != LDAP_SUCCESS) {
+ 		fprintf(stderr, "CRAP");
+ 		exit(1);
+ 	}
+ 
+ 	if ((ld = ldap_open(lud->lud_host, lud->lud_port)) == NULL)
+ 		return (FAIL);
+ 
+ 	if (ldap_simple_bind_s(ld, NULL, NULL) != LDAP_SUCCESS) {
+ 		ldap_unbind_s(ld);
+ 		return (FAIL);
+ 	}
+ 
+ 	/* how many RFC 2254 characters need escaping in the value ?? */
+         for (bp = peerdn; bp && *bp; bp++) {
+ 		switch (*bp) {
+ 			case '*':
+ 			case '(':
+ 			case ')':
+ 			case '\0':
+ 			case '\\':
+ 				++escapes; break;
+ 		}
+ 	}
+ 	if ((escapeddn = malloc(strlen(peerdn) + (escapes * 3) + 1)) == NULL)
+ 		return (FAIL);
+ 
+ 	tp = escapeddn;
+ 	*tp = 0;
+ 	for (bp = peerdn; bp && *bp; bp++) {
+ 		switch (*bp) {
+ 			case '*':
+ 			case '(':
+ 			case ')':
+ 			case '\0':
+ 			case '\\':
+ 				sprintf(tp, "\\%02x", *bp);
+ 				tp += 3;
+ 				break;
+ 			default:
+ 				*tp++ = *bp;
+ 				*tp = 0;
+ 		}
+ 	}
+ 
+         /* How many SEPs do we have in the filter string?? */
+         for (bp = lud->lud_filter, n = 0; bp && *bp; bp++) {
+ 		if (*bp == SEP)
+ 			++n;
+         }
+ 
+         tp = filter = malloc(strlen(lud->lud_filter) +
+ 		(n * strlen(escapeddn)) + 1);
+ 
+         if (filter == NULL) {
+ 		ldap_unbind_s(ld);
+                 return (FAIL);
+ 	}
+ 
+ 	/* Build the filter string, replacing all occurrances of '@'
+ 	 * with the (possibly escaped) DN that we are searching for */
+         *tp = 0;
+         for (bp = lud->lud_filter, tp = filter; bp && *bp; bp++) {
+                 if (*bp != '@') {
+                         *tp++ = *bp;
+                         *tp = 0;
+                 } else {
+                         strcpy(tp, escapeddn);
+                         tp += strlen(escapeddn);
+                 }
+         }
+ 
+         log(LOG_NOTICE, "dispatch: filter=[%s]", filter);
+ 
+ 	free(escapeddn);
+ 
+         rc = ldap_search_s(ld, lud->lud_dn, lud->lud_scope, filter, lud->lud_attrs, 0, &res);
+         if (rc != LDAP_SUCCESS) {
+ 		ldap_unbind_s(ld);
+                 return (FAIL);
+         }
+ 
+         if (ldap_count_entries(ld, res) != 1) {
+ 		ldap_unbind_s(ld);
+                 return (FAIL);
+ 	}
+         if ((e = ldap_first_entry(ld, res)) == NULL) {
+ 		ldap_unbind_s(ld);
+                 return (FAIL);
+ 	}
+ 
+ 	rc = FAIL;
+         if ((vals = ldap_get_values(ld, e, lud->lud_attrs[0])) != NULL) {
+ 
+ 		/* If "commented" out, FAIL this entry */
+ 		if (*vals[0] != '#') {
+ 			strcpy(taddr, vals[0]);
+ 			rc = YES;
+ 		}
+ 		ldap_value_free(vals);
+ 	}
+ 
+ 	ldap_unbind_s(ld);
+ 	return (rc);
+ }
+ #endif /* USE_DISPATCH */

diff -r -c stunnel-4.04-orig/src/client.c stunnel-4.04/src/client.c
*** stunnel-4.04-orig/src/client.c	Wed Jan  1 20:04:39 2003
--- stunnel-4.04/src/client.c	Mon Sep 29 17:53:31 2003
***************
*** 73,78 ****
--- 73,81 ----
  static int make_sockets(int [2]);
  #endif
  static int connect_remote(CLI *c);
+ #ifdef USE_DISPATCH
+ static int dispatch_connect(CLI *c);
+ #endif
  static void reset(int, char *);
  
  int max_clients;
***************
*** 200,205 ****
--- 203,213 ----
      else
          c->bind_ip=0;
      /* Setup c->remote_fd, now */
+ #ifdef USE_DISPATCH
+     if(c->opt->option.dispatch) {
+ 	fd=dispatch_connect(c);
+     } else
+ #endif
      if(c->opt->option.remote) {
          c->resolved_addresses=NULL;
          fd=connect_remote(c);
***************
*** 903,908 ****
--- 911,1030 ----
      }
      return -1;
  }
+ 
+ #ifdef USE_DISPATCH
+ static int dispatch_connect(CLI *c) { /* connect to remote host */
+     struct sockaddr_in addr;
+     u32 *list;
+     int error;
+     int s; /* destination socket */
+     u16 dport;
+     X509 *peer;
+     char subject[STRLEN], taddr[STRLEN];
+     int dispatch(char *ldapurl, char *peerdn, char *addr);
+ 
+     memset(&addr, 0, sizeof(addr));
+     addr.sin_family=AF_INET;
+ 
+     if(! c->opt->option.dispatch) {
+             log(LOG_ERR, "what are you doing in dispatch?");
+ 	    return -1;
+     }
+     if(! c->ssl) {
+             log(LOG_ERR, "cannot dispatch without SSL.");
+ 	    return -1;
+     }
+ 
+ 	peer=SSL_get_peer_certificate(c->ssl);
+ 	if(peer) {
+ 		X509_NAME_oneline(X509_get_subject_name(peer), subject, STRLEN);
+ 		safestring(subject);
+ 		X509_free(peer);
+ 	}
+ 	log(LOG_NOTICE, "dispatch: peer is %s", subject);
+ 
+ 
+ 	enter_critical_section(CRIT_LDAP);
+ 	if (dispatch(c->opt->remote_address, subject, taddr) < 0) {
+ 		leave_critical_section(CRIT_LDAP);
+ 		return -1;
+ 	}
+ 	leave_critical_section(CRIT_LDAP);
+ 
+ 	if (name2nums(taddr, "127.0.0.1", &list, &dport) == 0) {
+ 		/* No host resolved */
+ 		return -1;
+ 	}
+     /* rest of routine swiped from connect_remote  */
+ 
+     for(; *list+1; list++) { /* same as (signed)*list!=-1 */
+         if((s=socket(AF_INET, SOCK_STREAM, 0))<0) {
+             sockerror("remote socket");
+             return -1;
+         }
+         if(alloc_fd(s))
+             return -1;
+ 
+         if(c->bind_ip) { /* explicit local bind or transparent proxy */
+             addr.sin_addr.s_addr=c->bind_ip;
+             addr.sin_port=htons(0);
+             if(bind(s, (struct sockaddr *)&addr, sizeof(addr))<0) {
+                 sockerror("bind transparent");
+                 closesocket(s);
+                 return -1;
+             }
+         }
+ 
+         /* try to connect for the 1st time */
+         addr.sin_port=dport;
+         addr.sin_addr.s_addr=*list;
+         safe_ntoa(c->connecting_address, addr.sin_addr);
+         log(LOG_NOTICE, "dispatching %s to %s:%d", subject,
+             c->connecting_address, ntohs(addr.sin_port));
+         if(!connect(s, (struct sockaddr *)&addr, sizeof(addr)))
+             return s; /* no error -> success */
+         error=get_last_socket_error();
+         switch(error) {
+         case EINPROGRESS: /* retry */
+             log(LOG_DEBUG, "remote connect #1: EINPROGRESS: retrying");
+             break;
+         case EWOULDBLOCK: /* retry */
+             log(LOG_DEBUG, "remote connect #1: EWOULDBLOCK: retrying");
+             break;
+         default:
+             log(LOG_ERR, "remote connect #1 (%s:%d): %s (%d)",
+                 c->connecting_address, ntohs(addr.sin_port),
+                 my_strerror(error), error);
+             closesocket(s);
+             continue; /* Next IP */
+         }
+ 
+         /* wait until the connecting socket is ready for write */
+         if(waitforsocket(s, 1 /* write */, c->opt->timeout_busy)<1) {
+             closesocket(s);
+             continue; /* timeout or error */
+         }
+ 
+         /* try to connect for the 2nd time */
+         if(!connect(s, (struct sockaddr *)&addr, sizeof(addr)))
+             return s; /* no error -> success */
+         error=get_last_socket_error();
+         switch(error) {
+         case EINVAL: /* WIN32 is strange... */
+             log(LOG_DEBUG, "remote connect #2: EINVAL: ok");
+         case EISCONN: /* ok */
+             return s; /* success */
+         default:
+             log(LOG_ERR, "remote connect #2 (%s:%d): %s (%d)",
+                 c->connecting_address, ntohs(addr.sin_port),
+                 my_strerror(error), error);
+             closesocket(s);
+             continue; /* Next IP */
+         }
+ 	}
+     return -1;
+ }
+ #endif /* USE_DISPATCH */
  
  static void reset(int fd, char *txt) {
      /* Set lingering on a socket if needed*/

diff -r -c stunnel-4.04-orig/src/options.c stunnel-4.04/src/options.c
*** stunnel-4.04-orig/src/options.c	Wed Jan  1 15:21:58 2003
--- stunnel-4.04/src/options.c	Mon Sep 29 17:59:50 2003
***************
*** 616,621 ****
--- 616,644 ----
          break;
      }
  
+ #ifdef USE_DISPATCH
+     /* dispatch */
+     switch(cmd) {
+     case CMD_INIT:
+         section->option.dispatch=0;
+         section->remote_address=NULL;
+         section->remoteport=0;
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "dispatch"))
+             break;
+         section->option.dispatch=1;
+         section->remote_address=stralloc(arg);	/* LDAPURL */
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = LDAPURL. dispatch via LDAP", 
+             "dispatch");
+         break;
+     }
+ #endif /* USE_DISPATCH */
+ 
      /* delay */
      switch(cmd) {
      case CMD_INIT:
***************
*** 987,992 ****
--- 1010,1018 ----
  #else
      if((unsigned int)section->option.accept +
              (unsigned int)section->option.program +
+ #ifdef USE_DISPATCH
+             (unsigned int)section->option.dispatch +
+ #endif /* USE_DISPATCH */
              (unsigned int)section->option.remote != 2)
  #endif
          return "Each service section must define exactly two endpoints";

diff -r -c stunnel-4.04-orig/src/prototypes.h stunnel-4.04/src/prototypes.h
*** stunnel-4.04-orig/src/prototypes.h	Wed Jan  1 15:33:54 2003
--- stunnel-4.04/src/prototypes.h	Mon Sep 29 17:59:23 2003
***************
*** 69,75 ****
  
  typedef enum {
      CRIT_KEYGEN, CRIT_LIBWRAP, CRIT_NTOA, CRIT_CLIENTS, CRIT_WIN_LOG,
!     CRIT_SECTIONS
  } section_code;
  
  void enter_critical_section(section_code);
--- 69,75 ----
  
  typedef enum {
      CRIT_KEYGEN, CRIT_LIBWRAP, CRIT_NTOA, CRIT_CLIENTS, CRIT_WIN_LOG,
!     CRIT_LDAP, CRIT_SECTIONS
  } section_code;
  
  void enter_critical_section(section_code);
***************
*** 169,174 ****
--- 169,177 ----
          unsigned int delayed_lookup:1;
          unsigned int accept:1;
          unsigned int remote:1;
+ #ifdef USE_DISPATCH
+         unsigned int dispatch:1;
+ #endif
  #ifndef USE_WIN32
          unsigned int program:1;
          unsigned int pty:1;
