CHUNKING/DKIM: fix handling of lines having a leading dot
[exim.git] / src / src / auths / cyrus_sasl.c
index d454c7732b72e4261ad06cb84b5b5593c8ce2b21..bab2be36c4780bea78d921ef5deeace8982bf1ad 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* This code was originally contributed by Matthew Byng-Maddick */
@@ -25,7 +25,9 @@ in a dummy argument to stop even pickier compilers complaining about infinite
 loops. */
 
 #ifndef AUTH_CYRUS_SASL
-static void dummy(int x) { dummy(x-1); }
+static void dummy(int x);
+static void dummy2(int x) { dummy(x-1); }
+static void dummy(int x) { dummy2(x-1); }
 #else
 
 
@@ -95,7 +97,7 @@ auth_cyrus_sasl_init(auth_instance *ablock)
 {
 auth_cyrus_sasl_options_block *ob =
   (auth_cyrus_sasl_options_block *)(ablock->options_block);
-uschar *list, *listptr, *buffer;
+const uschar *list, *listptr, *buffer;
 int rc, i;
 unsigned int len;
 uschar *rs_point, *expanded_hostname;
@@ -144,7 +146,7 @@ if( rc != SASL_OK )
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
       "couldn't initialise Cyrus SASL server connection.", ablock->name);
 
-rc=sasl_listmech(conn, NULL, "", ":", "", (const char **)(&list), &len, &i);
+rc=sasl_listmech(conn, NULL, "", ":", "", (const char **)&list, &len, &i);
 if( rc != SASL_OK )
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
       "couldn't get Cyrus SASL mechanism list.", ablock->name);
@@ -205,7 +207,7 @@ uschar *debug = NULL;   /* Stops compiler complaining */
 sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}};
 sasl_conn_t *conn;
 char *realm_expanded;
-int rc, firsttime=1, clen, negotiated_ssf;
+int rc, i, firsttime=1, clen, *negotiated_ssf_ptr=NULL, negotiated_ssf;
 unsigned int inlen, outlen;
 
 input=data;
@@ -226,7 +228,7 @@ if((hname == NULL) ||
 
 if(inlen)
   {
-  clen=auth_b64decode(input, &clear);
+  clen = b64decode(input, &clear);
   if(clen < 0)
     {
     return BAD64;
@@ -256,23 +258,81 @@ if( rc != SASL_OK )
   return DEFER;
   }
 
-if (tls_cipher)
+if (tls_in.cipher)
   {
-  rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, &tls_bits);
+  rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, (sasl_ssf_t *) &tls_in.bits);
   if (rc != SASL_OK)
     {
     HDEBUG(D_auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n",
-        tls_bits, sasl_errstring(rc, NULL, NULL));
+        tls_in.bits, sasl_errstring(rc, NULL, NULL));
     auth_defer_msg = US"couldn't set Cyrus SASL EXTERNAL SSF";
     sasl_done();
     return DEFER;
     }
   else
-    HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_bits);
+    HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_in.bits);
   }
 else
   HDEBUG(D_auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n");
 
+/* So sasl_setprop() documents non-shorted IPv6 addresses which is incredibly
+annoying; looking at cyrus-imapd-2.3.x source, the IP address is constructed
+with their iptostring() function, which just wraps
+getnameinfo(..., NI_NUMERICHOST|NI_NUMERICSERV), which is equivalent to the
+inet_ntop which we wrap in our host_ntoa() function.
+
+So the docs are too strict and we shouldn't worry about :: contractions. */
+
+/* Set properties for remote and local host-ip;port */
+for (i=0; i < 2; ++i)
+  {
+  struct sockaddr_storage ss;
+  int (*query)(int, struct sockaddr *, socklen_t *);
+  int propnum, port;
+  const uschar *label;
+  uschar *address, *address_port;
+  const char *s_err;
+  socklen_t sslen;
+
+  if (i)
+    {
+    query = &getpeername;
+    propnum = SASL_IPREMOTEPORT;
+    label = CUS"peer";
+    }
+  else
+    {
+    query = &getsockname;
+    propnum = SASL_IPLOCALPORT;
+    label = CUS"local";
+    }
+
+  sslen = sizeof(ss);
+  rc = query(fileno(smtp_in), (struct sockaddr *) &ss, &sslen);
+  if (rc < 0)
+    {
+    HDEBUG(D_auth)
+      debug_printf("Failed to get %s address information: %s\n",
+          label, strerror(errno));
+    break;
+    }
+
+  address = host_ntoa(-1, &ss, NULL, &port);
+  address_port = string_sprintf("%s;%d", address, port);
+
+  rc = sasl_setprop(conn, propnum, address_port);
+  if (rc != SASL_OK)
+    {
+    s_err = sasl_errdetail(conn);
+    HDEBUG(D_auth)
+      debug_printf("Failed to set %s SASL property: [%d] %s\n",
+          label, rc, s_err ? s_err : "<unknown reason>");
+    break;
+    }
+  HDEBUG(D_auth) debug_printf("Cyrus SASL set %s hostport to: %s\n",
+      label, address_port);
+  }
+
 rc=SASL_CONTINUE;
 
 while(rc==SASL_CONTINUE)
@@ -303,7 +363,7 @@ while(rc==SASL_CONTINUE)
     HDEBUG(D_auth) debug=string_copy(input);
     if(inlen)
       {
-      clen=auth_b64decode(input, &clear);
+      clen = b64decode(input, &clear);
       if(clen < 0)
        {
         sasl_dispose(&conn);
@@ -392,7 +452,7 @@ while(rc==SASL_CONTINUE)
       debug_printf("Cyrus SASL %s authentication succeeded for %s\n",
           ob->server_mech, auth_vars[0]);
 
-    rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf));
+    rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf_ptr));
     if (rc != SASL_OK)
       {
       HDEBUG(D_auth)
@@ -405,6 +465,7 @@ while(rc==SASL_CONTINUE)
       sasl_done();
       return FAIL;
       }
+    negotiated_ssf = *negotiated_ssf_ptr;
     HDEBUG(D_auth)
       debug_printf("Cyrus SASL %s negotiated SSF: %d\n", ob->server_mech, negotiated_ssf);
     if (negotiated_ssf > 0)