*** /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 + #include + #include + #include + #include + #include + #include + + #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;