components/proftpd/mod_gss-patches/ip4-mapped-gss-channel-bindings.patch
author Tomas Klacko <tomas.klacko@oracle.com>
Mon, 02 Jul 2012 11:16:01 -0700
changeset 902 908943bbfdb9
permissions -rw-r--r--
7087284 proftpd using GSS fails for IPv6

--- a/mod_gss.c.in
+++ b/mod_gss.c.in
@@ -1412,6 +1412,87 @@ MODRET gss_auth(cmd_rec *cmd) {
     return HANDLED(cmd);
 }
 
+#ifdef USE_IPV6 /* { */
+#define IPV6_STR_SIZE   128
+
+static int ip6_to_str(struct in6_addr* addr, char* buf, int size) {
+
+    const char *err;
+
+    if(size<IPV6_STR_SIZE)
+        return 0;
+
+    memset(buf, 0, size);
+    err=inet_ntop(AF_INET6, addr, buf, size-1);
+    if(err!=buf)
+        return 0;
+
+    return 1;
+}
+
+static int ip6_to_ip4(struct in6_addr *ip6, struct in_addr *ip4) {
+
+    char buf[IPV6_STR_SIZE];
+
+    if (!ip6_to_str(ip6, buf, IPV6_STR_SIZE))
+        return 0;
+
+    const char *ip4_str=strrchr(buf, ':');
+    if (ip4_str == 0)
+        return 0;
+
+    ip4_str++;
+    if (!inet_aton(ip4_str, ip4))
+        return 0;
+
+    return 1;
+}
+
+static int set_chan_v4mapped(
+    gss_channel_bindings_t chan, struct in_addr *ia, struct in_addr *aa) {
+
+    if (!ip6_to_ip4(&(session.c->remote_addr->na_addr.v6.sin6_addr), ia))
+        return 0;
+
+    if (!ip6_to_ip4(&(session.c->local_addr->na_addr.v6.sin6_addr), aa))
+        return 0;
+
+    chan->initiator_addrtype = GSS_C_AF_INET;
+    chan->initiator_address.length = sizeof(struct in_addr);
+    chan->initiator_address.value = ia;
+
+    chan->acceptor_addrtype = GSS_C_AF_INET;
+    chan->acceptor_address.length = sizeof(struct in_addr);
+    chan->acceptor_address.value = aa;
+
+    chan->application_data.length = 0;
+    chan->application_data.value = 0;
+
+    return 1;
+}
+
+static int try_v4mapped() {
+
+    struct in6_addr* addr;
+
+    if (pr_netaddr_get_family(session.c->remote_addr) != AF_INET6)
+        return 0;
+
+    if (pr_netaddr_get_family(session.c->local_addr) != AF_INET6)
+        return 0;
+
+    addr = (struct in6_addr*)pr_netaddr_get_inaddr(session.c->remote_addr);
+    if (!IN6_IS_ADDR_V4MAPPED(addr))
+        return 0;
+
+    addr = (struct in6_addr*)pr_netaddr_get_inaddr(session.c->local_addr);
+    if (!IN6_IS_ADDR_V4MAPPED(addr))
+        return 0;
+
+    return 1;
+}
+#endif /* } */
+
 /*
    AUTHENTICATION/SECURITY DATA (ADAT)
 
@@ -1527,6 +1608,12 @@ MODRET gss_adat(cmd_rec *cmd) {
     char *gbuf ;
   
     gss_channel_bindings_t chan=GSS_C_NO_CHANNEL_BINDINGS;
+    gss_channel_bindings_t chan_sl=GSS_C_NO_CHANNEL_BINDINGS;
+#ifdef USE_IPV6
+    gss_channel_bindings_t chan_v4m=GSS_C_NO_CHANNEL_BINDINGS;
+    struct in_addr ia;
+    struct in_addr aa;
+#endif
 
     if (!gss_engine)
         return DECLINED(cmd);
@@ -1631,13 +1718,22 @@ MODRET gss_adat(cmd_rec *cmd) {
 	    continue;
 	}
 
+        chan_sl = chan;
+#ifdef USE_IPV6
+        if (try_v4mapped()) {
+            chan_v4m = pcalloc(cmd->tmp_pool,sizeof(*chan_v4m));
+            if (set_chan_v4mapped(chan_v4m, &ia, &aa))
+                chan_sl = chan_v4m;
+        }
+#endif
+
 	found++;
 	gcontext = GSS_C_NO_CONTEXT;
 	accept_maj = gss_accept_sec_context(&accept_min,
 	   				    &gcontext, /* context_handle */
 					    server_creds, /* verifier_cred_handle */
 					    &tok, /* input_token */
-					    chan, /* channel bindings */
+					    chan_sl, /* channel bindings */
 					    &client, /* src_name */
 					    &mechid, /* mech_type */
 					    &out_tok, /* output_token */