]> diplodocus.org Git - nmh/blobdiff - sbr/netsec.c
- Fixed bcc to work with sendmail/pipe [Bug 55700].
[nmh] / sbr / netsec.c
index 3b546a30d45e94c08ad0226217b77bd9901b7ec6..a4ede21042f184297975e81b7659c47365480a64 100644 (file)
@@ -6,10 +6,13 @@
  * complete copyright information.
  */
 
-#include <h/mh.h>
-#include <h/utils.h>
-#include <h/netsec.h>
-#include <h/oauth.h>
+#include "h/mh.h"
+#include "credentials.h"
+#include "getcpy.h"
+#include "brkstring.h"
+#include "h/utils.h"
+#include "h/netsec.h"
+#include "h/oauth.h"
 #include <stdarg.h>
 #include <sys/select.h>
 #include "base64.h"
@@ -30,7 +33,7 @@ static int netsec_get_user(void *context, int id, const char **result,
 static int netsec_get_password(sasl_conn_t *conn, void *context, int id,
                               sasl_secret_t **psecret);
 
-static int sasl_initialized = 0;
+static bool sasl_initialized;
 
 #define SASL_MAXRECVBUF 65536
 #endif /* CYRUS_SASL */
@@ -39,7 +42,7 @@ static int sasl_initialized = 0;
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 
-static int tls_initialized = 0;
+static bool tls_initialized;
 static SSL_CTX *sslctx = NULL;         /* SSL Context */
 
 #endif /* TLS_SUPPORT */
@@ -288,7 +291,8 @@ netsec_set_snoop(netsec_context *nsc, int snoop)
  * Set the snoop callback for this connection.
  */
 
-void netsec_set_snoop_callback(netsec_context *nsc,
+void
+netsec_set_snoop_callback(netsec_context *nsc,
                               netsec_snoop_callback callback, void *context)
 {
     nsc->ns_snoop_cb = callback;
@@ -319,7 +323,7 @@ netsec_b64_snoop_decoder(netsec_context *nsc, const char *string, size_t len,
        len -= offset;
     }
 
-    if (decodeBase64(string, &decoded, &decodedlen, 1, NULL) == OK) {
+    if (decodeBase64(string, &decoded, &decodedlen, 1) == OK) {
        /*
         * Some mechanisms produce large binary tokens, which aren't really
         * readable.  So let's do a simple heuristic.  If the token is greater
@@ -806,6 +810,7 @@ netsec_vprintf(netsec_context *nsc, char **errstr, const char *format,
               va_list ap)
 {
     int rc;
+    va_list apcopy;
 
     /*
      * Cheat a little.  If we can fit the data into our outgoing buffer,
@@ -813,8 +818,10 @@ netsec_vprintf(netsec_context *nsc, char **errstr, const char *format,
      */
 
 retry:
+    va_copy(apcopy, ap);
     rc = vsnprintf((char *) nsc->ns_outptr,
-                  nsc->ns_outbufsize - nsc->ns_outbuflen, format, ap);
+                  nsc->ns_outbufsize - nsc->ns_outbuflen, format, apcopy);
+    va_end(apcopy);
 
     if (rc >= (int) (nsc->ns_outbufsize - nsc->ns_outbuflen)) {
        /*
@@ -830,7 +837,7 @@ retry:
             * At that point, just give up.
             */
            netsec_err(errstr, "Internal error: wanted to printf() a total of "
-                      "%d bytes, but our buffer size was only %d bytes",
+                      "%d bytes, but our buffer size was only %d bytes",
                       rc, nsc->ns_outbufsize);
            return NOTOK;
        }
@@ -919,7 +926,7 @@ netsec_flush(netsec_context *nsc, char **errstr)
                if (nsc->ns_snoop_savebuf) {
                    cb_len += strlen(nsc->ns_snoop_savebuf);
                    nsc->ns_snoop_savebuf = mh_xrealloc(nsc->ns_snoop_savebuf,
-                                               outlen);
+                                                       outlen);
                    ptr = nsc->ns_snoop_savebuf;
                } else {
                    ptr = snoopoutbuf;
@@ -1032,7 +1039,7 @@ netsec_set_sasl_params(netsec_context *nsc, const char *service,
                       sasl_errstring(retval, NULL, NULL));
            return NOTOK;
        }
-       sasl_initialized++;
+       sasl_initialized = true;
     }
 
     /*
@@ -1103,7 +1110,8 @@ netsec_set_sasl_params(netsec_context *nsc, const char *service,
  * library when asked.
  */
 
-int netsec_get_user(void *context, int id, const char **result,
+int
+netsec_get_user(void *context, int id, const char **result,
                    unsigned int *len)
 {
     netsec_context *nsc = (netsec_context *) context;
@@ -1183,6 +1191,22 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
     int rc;
 #endif /* CYRUS_SASL || OAUTH_SUPPORT */
 
+    /*
+     * Output some SASL information if snoop is turned on
+     */
+
+    if (nsc->ns_snoop) {
+       fprintf(stderr, "SASL mechanisms supported by server: %s\n", mechlist);
+
+       if (nsc->sasl_mech) {
+               fprintf(stderr, "User has requested SASL mechanism: %s\n",
+                       nsc->sasl_mech);
+       } else {
+               fprintf(stderr, "No SASL mech selected, will pick "
+                       "the best mech supported by SASL library\n");
+       }
+    }
+
     /*
      * If we've been passed a requested mechanism, check our mechanism
      * list from the protocol.  If it's not supported, return an error.
@@ -1221,6 +1245,10 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
         * error message.
         */
 
+       if (nsc->ns_snoop) {
+               fprintf(stderr, "Using internal XOAUTH2 mechanism\n");
+       }
+
        if (! nsc->oauth_service) {
            netsec_err(errstr, "Internal error: OAuth2 service name not given");
            return NOTOK;
@@ -1232,7 +1260,7 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
                               &xoauth_client_res, &xoauth_client_res_len,
                               nsc->ns_snoop ? stderr : NULL) != OK) {
            netsec_err(errstr, "Internal error: Unable to get OAuth2 "
-                      "bearer token");
+                      "bearer token");
            return NOTOK;
        }
 
@@ -1283,6 +1311,21 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
      * messages.
      */
 
+    if (nsc->ns_snoop) {
+       const char *client_mechlist;
+
+       rc = sasl_listmech(nsc->sasl_conn, NULL, NULL, " ", NULL,
+                          &client_mechlist, NULL, NULL);
+
+       if (rc != SASL_OK) {
+               fprintf(stderr, "Unable to get client mechlist: %s\n",
+                       sasl_errstring(rc, NULL, NULL));
+       } else {
+               fprintf(stderr, "Client supported SASL mechanisms: %s\n",
+                       client_mechlist);
+       }
+    }
+
     ZERO(&secprops);
     secprops.maxbufsize = SASL_MAXRECVBUF;
 
@@ -1296,6 +1339,12 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
 #endif /* TLS_SUPPORT */
                UINT_MAX;
 
+#ifdef TLS_SUPPORT
+    if (nsc->ns_snoop && nsc->tls_active)
+       fprintf(stderr, "SASL security layers disabled due to the use "
+               "of TLS\n");
+#endif /* TLS_SUPPORT */
+
     rc = sasl_setprop(nsc->sasl_conn, SASL_SEC_PROPS, &secprops);
 
     if (rc != SASL_OK) {
@@ -1310,7 +1359,7 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
      */
 
     rc = sasl_client_start(nsc->sasl_conn,
-                          nsc->sasl_mech ? nsc->sasl_mech : mechlist, NULL,
+                          nsc->sasl_mech ? nsc->sasl_mech : mechlist, NULL,
                           (const char **) &saslbuf, &saslbuflen,
                           &chosen_mech);
 
@@ -1322,6 +1371,9 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
 
     nsc->sasl_chosen_mech = getcpy(chosen_mech);
 
+    if (nsc->ns_snoop)
+       fprintf(stderr, "Chosen sasl mechanism: %s\n", chosen_mech);
+
     if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, NULL, 0,
                           nsc->sasl_proto_context, errstr) != OK)
        return NOTOK;
@@ -1331,7 +1383,7 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
      */
 
     while (rc == SASL_CONTINUE) {
-       /*
+       /*
         * Call our SASL callback, which will handle the details of
         * reading data from the network.
         */
@@ -1396,6 +1448,10 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
     nsc->sasl_ssf = *ssf;
 
     if (nsc->sasl_ssf > 0) {
+       if (nsc->ns_snoop)
+           fprintf(stderr, "SASL security layer negotiated, SASL will "
+                   "perform encryption\n");
+
        rc = sasl_getprop(nsc->sasl_conn, SASL_MAXOUTBUF,
                          (const void **) &outbufmax);
 
@@ -1448,6 +1504,15 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
        }
 
        nsc->sasl_seclayer = 1;
+    } else if (nsc->ns_snoop) {
+       fprintf(stderr, "SASL Security layer NOT negotiated, SASL will NOT "
+               "perform encryption\n");
+#ifdef TLS_SUPPORT
+       if (nsc->tls_active) {
+           fprintf(stderr, "Encryption will be handled by TLS\n");
+       } else
+#endif /* TLS_SUPPORT */
+           fprintf(stderr, "Connection will NOT be encrypted, use caution\n");
     }
 
     return OK;
@@ -1479,6 +1544,21 @@ netsec_get_sasl_mechanism(netsec_context *nsc)
     return nsc->sasl_chosen_mech;
 }
 
+/*
+ * Return the negotiated SASL strength security factor (SSF)
+ */
+
+int
+netsec_get_sasl_ssf(netsec_context *nsc)
+{
+#ifdef CYRUS_SASL
+    return nsc->sasl_ssf;
+#else /* CYRUS_SASL */
+    NMH_UNUSED(nsc);
+    return 0;
+#endif /* CYRUS_SASL */
+}
+
 /*
  * Set an OAuth2 service name, if we support it.
  */
@@ -1536,7 +1616,7 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr)
                return NOTOK;
            }
 
-           tls_initialized++;
+           tls_initialized = true;
        }
 
        if (nsc->ns_readfd == -1 || nsc->ns_writefd == -1) {
@@ -1640,7 +1720,7 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr)
 
        if (! ssl_bio) {
            netsec_err(errstr, "Unable to create a SSL BIO: %s",
-                      ERR_error_string(ERR_get_error(), NULL));
+                      ERR_error_string(ERR_get_error(), NULL));
            SSL_free(ssl);
            return NOTOK;
        }
@@ -1765,7 +1845,7 @@ netsec_err(char **errstr, const char *fmt, ...)
     int rc = 127;
 
     if (! errstr)
-       return;
+       return;
 
     do {
        errbufsize = rc + 1;