Package: stunnel4
Version: 2:4.070-2
Severity: wishlist
Tags: patch

Hello, 

Included is the dunbar-proxy-connect patch updated against version 4.07.
Could you include it in your debian package and forward it to upstream?

Thanks in advance, Peter

-- System Information:
Debian Release: 3.1
  APT prefers unstable
  APT policy: (990, 'unstable'), (500, 'testing')
Architecture: i386 (i686)
Kernel: Linux 2.6.10-my-2
Locale: [EMAIL PROTECTED], LC_CTYPE=it_IT (charmap=ISO-8859-1)

Versions of packages stunnel4 depends on:
ii  libc6                       2.3.2.ds1-20 GNU C Library: Shared libraries an
ii  libssl0.9.7                 0.9.7e-3     SSL shared libraries
ii  libwrap0                    7.6.dbs-6    Wietse Venema's TCP wrappers libra
ii  netbase                     4.19         Basic TCP/IP networking system
ii  openssl                     0.9.7e-3     Secure Socket Layer (SSL) binary a

-- no debconf information
diff -ubdNr stunnel4-4.070-original/src/client.c stunnel4-4.070-patched/src/client.c
--- stunnel4-4.070-original/src/client.c	2005-01-02 22:35:22.000000000 +0100
+++ stunnel4-4.070-patched/src/client.c	2005-01-18 11:52:39.000000000 +0100
@@ -75,6 +75,7 @@
 static int connect_remote(CLI *c);
 static int connect_wait(int, int);
 static void reset(int, char *);
+int connect_to_finaldest(CLI *c, int s);
 
 int max_clients;
 #ifndef USE_WIN32
@@ -952,7 +953,8 @@
         s_ntop(c->connecting_address, &addr);
         s_log(LOG_DEBUG, "%s connecting %s",
             c->opt->servname, c->connecting_address);
-        if(!connect(s, &addr.sa, addr_len(addr)))
+        if(!connect(s, &addr.sa, addr_len(addr))
+            && !connect_to_finaldest(c, s))
             return s; /* no error -> success (should not be possible) */
         error=get_last_socket_error();
         if(error!=EINPROGRESS && error!=EWOULDBLOCK) {
@@ -962,7 +964,11 @@
             continue; /* next IP */
         }
         if(!connect_wait(s, c->opt->timeout_connect))
+	  {
+	    /* we got a connection */
+	    if (!connect_to_finaldest(c, s))
             return s; /* success! */
+	  }
         closesocket(s); /* error -> next IP */
     }
     return -1;
@@ -1015,4 +1021,292 @@
         log_error(LOG_DEBUG, get_last_socket_error(), txt);
 }
 
+/* 
+ * Base 64 encoding algorithm from: Bob Deblier <[EMAIL PROTECTED]>
+ * Modified by Daniel Savard <[EMAIL PROTECTED]> to accept char *
+ */
+static const char* to_b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+char* b64enc(const char* data) {    
+    int divider = strlen(data) / 3;
+    int remainder = strlen(data) % 3;
+    int chars = divider*4 + remainder + 1;
+    char* string = (char*) malloc(chars + 1);
+
+    if (string) {
+        register char* buf = string;
+        chars = 0;
+        while (divider > 0) {
+            buf[0] = to_b64[ (data[0] >> 2) & 0x3f];
+            buf[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)];
+            buf[2] = to_b64[((data[1] << 2) & 0x3c) + ((data[2] >> 6) & 0x3)];
+            buf[3] = to_b64[ data[2] & 0x3f];
+            data += 3;
+            buf += 4;
+            divider--;
+            chars += 4;
+        }
+
+        switch (remainder) {
+            case 2:
+                buf[0] = to_b64[ (data[0] >> 2) & 0x3f];
+                buf[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)];
+                buf[2] = to_b64[ (data[1] << 2) & 0x3c];
+                buf[3] = '=';
+                buf += 4;
+                chars += 4;
+                break;
+            case 1:
+                buf[0] = to_b64[ (data[0] >> 2) & 0x3f];
+                buf[1] = to_b64[ (data[0] << 4) & 0x30];
+                buf[2] = '=';
+                buf[3] = '=';
+                buf += 4;
+                chars += 4;
+                break;
+        }
+
+        *buf = '\0';
+    }
+
+return string;
+}
+
+/*
+ *  Base 64 decoding algorithm from: Bob Deblier <[EMAIL PROTECTED]> 
+ *  Modified by Daniel Savard <[EMAIL PROTECTED]> to return char *
+ */
+char* b64dec(const char* string)
+{
+    /* return a decoded char string, or a null pointer in case of failure */
+    char* data = NULL;
+
+    if (string) {
+        register int length = strlen(string);
+
+        /* do a format verification first */
+        if (length > 0) {
+            register int count = 0, rem = 0;
+            register const char* tmp = string;
+
+            while (length > 0) {
+                register int skip = strspn(tmp, to_b64);
+                count += skip;
+                length -= skip;
+                tmp += skip;
+                if (length > 0) {
+                    register int i, vrfy = strcspn(tmp, to_b64);
+
+                    for (i = 0; i < vrfy; i++) {
+                        if (isspace(tmp[i]))
+                            continue;
+
+                        if (tmp[i] == '=') {
+                            /* we should check if we're close to the end of the string */
+                            rem = count % 4;
+
+                            /* rem must be either 2 or 3, otherwise no '=' should be here */
+                            if (rem < 2)
+                                return NULL;
+
+                            /* end-of-message recognized */
+                            break;
+                        } else {
+                           /* Transmission error; RFC tells us to ignore this, but:
+                            *  - the rest of the message is going to even more corrupt since we're sliding bits out of place
+                            * If a message is corrupt, it should be dropped. Period.
+                            */
+                            return NULL;
+                        }
+                    }
+                   
+                    length -= vrfy;
+                    tmp += vrfy;
+                }
+            }
+
+            data = (unsigned char *)malloc((count / 4) * 3 + (rem ? (rem - 1) : 0));
+
+            if (data) {
+                if (count > 0) {
+                    register int i, qw = 0, tw = 0;
+
+                    length = strlen(tmp = string);
+
+                    for (i = 0; i < length; i++) {
+                        register char ch = string[i];
+                        register char bits = 0;
+
+                        if (isspace(ch))
+                            continue;
+
+                        if ((ch >= 'A') && (ch <= 'Z'))	{
+                            bits = (ch - 'A');
+                        } else if ((ch >= 'a') && (ch <= 'z')) {
+                            bits = (ch - 'a' + 26);
+                        } else if ((ch >= '0') && (ch <= '9')) {
+                            bits = (ch - '0' + 52);
+                        } else if (ch == '=') {
+                            break;
+                        }
+
+                        switch (qw++) {
+                            case 0:
+                                data[tw+0] = (bits << 2) & 0xfc;
+                                break;
+                            case 1:
+                                data[tw+0] |= (bits >> 4) & 0x03;
+                                data[tw+1] = (bits << 4) & 0xf0;
+                                break;
+                            case 2:
+                                data[tw+1] |= (bits >> 2) & 0x0f;
+                                data[tw+2] = (bits << 6) & 0xc0;
+                                break;
+                            case 3:
+                                data[tw+2] |= bits & 0x3f;
+                                break;
+                        }
+
+                        if (qw == 4) {
+                            qw = 0;
+                            tw += 3;
+                        }
+                    }
+
+                    data[tw] = '\0';
+                }
+            }
+        }
+    }
+
+return data;
+}
+
+/*
+ * Original https proxy algorithm from: Tan Swee Heng <[EMAIL PROTECTED]>
+ * Modified by Daniel Savard <[EMAIL PROTECTED]> to support basic authentication
+ */
+ int connect_to_finaldest(CLI *c, int s) {
+    char buff[STRLEN];
+    int len, code,position,num;
+    char httpsproxy_auth[STRLEN] = "";
+    char httpsproxy_useragent[STRLEN] = "";
+    
+    if (!c->opt->option.httpsproxy)
+        return 0;
+
+    if (c->opt->httpsproxy_auth != NULL) {
+        if (strchr(c->opt->httpsproxy_auth,':')) {
+            /* httpsproxy_auth in the form name:password' */
+            char *base64_auth = b64enc(c->opt->httpsproxy_auth);
+            s_log(LOG_DEBUG,"proxy: authenticate with '%s' -> '%s'\n",c->opt->httpsproxy_auth,base64_auth);
+            sprintf(httpsproxy_auth,"Proxy-Authorization: Basic %s\r\n",base64_auth);
+            free(base64_auth);
+        } else {
+            /* httpsproxy_auth already base64 encoded */
+            char *normal_auth = b64dec(c->opt->httpsproxy_auth);
+            s_log(LOG_DEBUG,"proxy: authenticate with '%s' -> '%s'\n",normal_auth,c->opt->httpsproxy_auth);
+            sprintf(httpsproxy_auth,"Proxy-Authorization: Basic %s\r\n",c->opt->httpsproxy_auth);
+            free(normal_auth);
+        }
+    } else {
+        s_log(LOG_DEBUG,"proxy: no authentication specified");
+    }
+
+    if (c->opt->httpsproxy_useragent != NULL) {
+        sprintf(httpsproxy_useragent,"User-Agent: %s\r\n",c->opt->httpsproxy_useragent);
+        s_log(LOG_DEBUG,"proxy: useragent '%s' -> '%s'\n",c->opt->httpsproxy_useragent,httpsproxy_useragent);	
+    } else {
+        s_log(LOG_DEBUG,"proxy: no useragent specified");
+    }
+
+#ifdef HAVE_SNPRINTF
+    len=snprintf(buff, STRLEN,
+#else
+    len=sprintf(buff,
+#endif
+        "CONNECT %s HTTP/1.0\r\n%s%s\r\n", 
+        c->opt->httpsproxy_dest_address,
+        httpsproxy_auth,
+        httpsproxy_useragent);
+
+
+	s_log(LOG_DEBUG, "me ---> proxy: %s", buff);
+        for(position=0;position<len;) {
+	  switch(num=writesocket(s, buff+position, len-position)) {
+	  case -1: /* error */
+	    switch(get_last_socket_error()) {
+	    case EINTR:
+	      s_log(LOG_DEBUG,
+		    "writesocket of proxy connect interrupted by a signal: retrying");
+	      break;
+	    case EWOULDBLOCK:
+	      s_log(LOG_NOTICE, "writesocket would block: retrying");
+	      break;
+	    default:
+	      sockerror("writesocket (httpsproxy)");
+	      closesocket(s);
+	      return -1;
+	    }
+	    break;
+	  case 0:
+	    s_log(LOG_DEBUG, "No data written to the proxy socket: retrying");
+	    break;
+	  default:
+	    position+=num;
+	  }
+        }
+    s_log(LOG_DEBUG, "done sending\n");
+
+
+    if(connect_wait(s, c->opt->timeout_busy)) {
+      s_log(LOG_ERR,"timeout while wainting for reply to command '%s'\n",
+	    buff);
+      return -1;
+    }
+
+
+    /* get a line */
+    for(position=0; (position == 0) || (buff[position-1] != '\n');) {
+      switch(num=readsocket(s, buff+position, STRLEN-1-position)) {
+            case -1:
+                switch(get_last_socket_error()) {
+                case EINTR:
+                    s_log(LOG_DEBUG,
+                        "readsocket for proxy interrupted by a signal: retrying");
+                    break;
+                case EWOULDBLOCK:
+		buff[position+num]='\0';
+                    s_log(LOG_NOTICE, "readsocket for proxy would block: retrying, got: '%s'",buff);
+                    break;
+                default:
+                    sockerror("readsocket for proxy");
+                    closesocket(s);
+                    return -1;
+                }
+                break;
+            case 0: /* close */
+                s_log(LOG_DEBUG, "Socket closed on read for proxy");
+                break;
+            default:
+                position+=num;
+            }
+    }
+
+    buff[position]='\0';
+    s_log(LOG_DEBUG, "proxy ---> me: %s", buff);
+
+    code = 0;
+    if(sscanf(buff, "HTTP/%*s %d %*s", &code) != 1) {
+        s_log(LOG_ERR, "error: %s", buff);
+        return -1;
+    }
+
+    if(code != 200) {
+        s_log(LOG_WARNING, "return code not 200: %s", buff);
+        return -1;
+    }
+
+    return 0;
+}
+
 /* End of client.c */
diff -ubdNr stunnel4-4.070-original/src/options.c stunnel4-4.070-patched/src/options.c
--- stunnel4-4.070-original/src/options.c	2004-12-31 09:53:40.000000000 +0100
+++ stunnel4-4.070-patched/src/options.c	2005-01-18 11:15:18.000000000 +0100
@@ -788,6 +788,84 @@
     }
 #endif
 
+    /* Daniel Savard <[EMAIL PROTECTED]>
+     * httpsproxy_auth
+     * Optional parameter to httpsproxy_dest to specify authentication 
+     * credential to the https proxy.  Value must be in form name:password
+     * or the base64 encoded value of the preceding form.
+     */
+    switch(cmd) {
+    case CMD_INIT:
+        section->httpsproxy_auth=NULL;
+        break;
+    case CMD_EXEC:
+        if(strcasecmp(opt, "httpsproxy_auth"))
+            break;
+        section->httpsproxy_auth=stralloc(arg);
+        return NULL; /* OK */
+    case CMD_DEFAULT:
+        break;
+    case CMD_HELP:
+        log_raw("%-15s = authentication for 'httpsproxy' must be userid:password",
+            "httpsproxy_auth");
+        break;
+    }
+
+    /* Daniel Savard <[EMAIL PROTECTED]>
+     * httpsproxy_dest
+     * When specified, the connect parameter will specify the name of a https
+     * proxy server and this parameter will be the final destination.
+     */
+    switch(cmd) {
+    case CMD_INIT:
+        section->option.httpsproxy=0;
+        section->httpsproxy_dest_address=NULL;
+	memset(&section->httpsproxy_dest_names, 0, sizeof(SOCKADDR_LIST));
+        section->httpsproxy_dest_names.addr[0].in.sin_family=AF_INET;
+        section->httpsproxy_dest_port=0;
+        break;
+    case CMD_EXEC:
+        if(strcasecmp(opt, "httpsproxy_dest"))
+            break;
+        section->option.httpsproxy=1;
+        section->httpsproxy_dest_address=stralloc(arg);
+
+	if(!section->option.delayed_lookup &&
+	   !name2addrlist(&section->httpsproxy_dest_names, arg, DEFAULT_LOOPBACK)) {
+            log_raw("Cannot resolve '%s' - delaying DNS lookup", arg);
+            section->option.delayed_lookup=1;
+        }
+        return NULL; /* OK */
+    case CMD_DEFAULT:
+        break;
+    case CMD_HELP:
+        log_raw("%-15s = [host:]port https proxy connect destination host:port",
+            "httpsproxy_dest");
+        break;
+    }
+
+    /* Daniel Savard <[EMAIL PROTECTED]>
+     * httpsproxy_useragent
+     * Optional parameter to httpsproxy_dest.  When specified, the specified 
+     * user-agent will be sent to the proxy
+     */
+    switch(cmd) {
+    case CMD_INIT:
+        section->httpsproxy_useragent=NULL;
+        break;
+    case CMD_EXEC:
+        if(strcasecmp(opt, "httpsproxy_useragent"))
+            break;
+        section->httpsproxy_useragent=stralloc(arg);
+        return NULL; /* OK */
+    case CMD_DEFAULT:
+        break;
+    case CMD_HELP:
+        log_raw("%-15s = useragent for 'httpsproxy'",
+            "httpsproxy_useragent");
+        break;
+    }
+
     /* ident */
     switch(cmd) {
     case CMD_INIT:
diff -ubdNr stunnel4-4.070-original/src/prototypes.h stunnel4-4.070-patched/src/prototypes.h
--- stunnel4-4.070-original/src/prototypes.h	2005-01-02 23:43:23.000000000 +0100
+++ stunnel4-4.070-patched/src/prototypes.h	2005-01-18 11:10:13.000000000 +0100
@@ -181,10 +181,12 @@
         /* service-specific data for client.c */
     int fd;        /* file descriptor accepting connections for this service */
     char *execname, **execargs; /* program name and arguments for local mode */
-    SOCKADDR_LIST local_addr, remote_addr;
+    SOCKADDR_LIST local_addr, remote_addr, httpsproxy_dest_names;
     SOCKADDR_LIST source_addr;
     char *username;
     char *remote_address;
+    char *httpsproxy_auth, *httpsproxy_useragent, *httpsproxy_dest_address;
+    unsigned short httpsproxy_dest_port;
     int timeout_busy; /* Maximum waiting for data time */
     int timeout_close; /* Maximum close_notify time */
     int timeout_connect; /* Maximum connect() time */
@@ -198,6 +200,43 @@
         unsigned int delayed_lookup:1;
         unsigned int accept:1;
         unsigned int remote:1;
+        unsigned int httpsproxy:1;
 #ifndef USE_WIN32
         unsigned int program:1;
         unsigned int pty:1;

Reply via email to