--- 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 */