]> diplodocus.org Git - nmh/blobdiff - sbr/netsec.c
Garbage-collect all of this unused code.
[nmh] / sbr / netsec.c
index 372732c3540ce986f9d215aa7ec5eb78fc9636c6..3fd31854f568c56655493f6fbf499a978931cd41 100644 (file)
@@ -56,6 +56,8 @@ static SSL_CTX *sslctx = NULL;                /* SSL Context */
 struct _netsec_context {
     int ns_fd;                 /* Descriptor for network connection */
     int ns_snoop;              /* If true, display network data */
+    int ns_snoop_noend;                /* If true, didn't get a CR/LF on last line */
+    netsec_snoop_callback ns_snoop_cb; /* Snoop output callback */
     int ns_timeout;            /* Network read timeout, in seconds */
     char *ns_userid;           /* Userid for authentication */
     unsigned char *ns_inbuffer;        /* Our read input buffer */
@@ -89,12 +91,6 @@ struct _netsec_context {
 #endif /* TLS_SUPPORT */
 };
 
-/*
- * Function to allocate error message strings
- */
-
-static void netsec_err(char **errstr, const char *format, ...);
-
 /*
  * Function to read data from the actual network socket
  */
@@ -128,6 +124,8 @@ netsec_init(void)
 
     nsc->ns_fd = -1;
     nsc->ns_snoop = 0;
+    nsc->ns_snoop_noend = 0;
+    nsc->ns_snoop_cb = NULL;
     nsc->ns_userid = NULL;
     nsc->ns_timeout = 60;      /* Our default */
     nsc->ns_inbufsize = NETSEC_BUFSIZE;
@@ -327,7 +325,7 @@ netsec_read(netsec_context *nsc, void *buffer, size_t size, char **errstr)
  */
 
 char *
-netsec_readline(netsec_context *nsc, char **errstr)
+netsec_readline(netsec_context *nsc, size_t *len, char **errstr)
 {
     unsigned char *ptr = nsc->ns_inptr;
     size_t count = 0, offset;
@@ -344,8 +342,25 @@ retry:
            if (count > 1 && *(ptr - 2) == '\r')
                ptr--;
            *--ptr = '\0';
+           if (len)
+               *len = ptr - nsc->ns_inptr;
            nsc->ns_inptr += count;
            nsc->ns_inbuflen -= count;
+           if (nsc->ns_snoop) {
+#ifdef CYRUS_SASL
+               if (nsc->sasl_seclayer)
+                   fprintf(stderr, "(sasl-encrypted) ");
+#endif /* CYRUS_SASL */
+#ifdef TLS_SUPPORT
+               if (nsc->tls_active)
+                   fprintf(stderr, "(tls-encrypted) ");
+#endif /* TLS_SUPPORT */
+               fprintf(stderr, "<= ");
+               if (nsc->ns_snoop_cb)
+                   nsc->ns_snoop_cb(nsc, sptr, strlen(sptr));
+               else
+                   fprintf(stderr, "%s\n", sptr);
+           }
            return sptr;
        }
     }
@@ -567,6 +582,11 @@ netsec_write(netsec_context *nsc, const void *buffer, size_t size,
     const unsigned char *bufptr = buffer;
     int rc, remaining;
 
+    /* Just in case */
+
+    if (size == 0)
+       return OK;
+
     /*
      * If TLS is active, then bypass all of our buffering logic; just
      * write it directly to our BIO.  We have a buffering BIO first in
@@ -624,6 +644,7 @@ netsec_write(netsec_context *nsc, const void *buffer, size_t size,
 
 /*
  * Our network printf() routine, which really just calls netsec_vprintf().
+ */
 
 int
 netsec_printf(netsec_context *nsc, char **errstr, const char *format, ...)
@@ -631,7 +652,7 @@ netsec_printf(netsec_context *nsc, char **errstr, const char *format, ...)
     va_list ap;
     int rc;
 
-    va_start(format, ap);
+    va_start(ap, format);
     rc = netsec_vprintf(nsc, errstr, format, ap);
     va_end(ap);
 
@@ -709,6 +730,34 @@ retry:
        }
     }
 
+    if (nsc->ns_snoop) {
+       int outlen = rc;
+       if (outlen > 0 && nsc->ns_outptr[outlen - 1] == '\n') {
+           outlen--;
+           if (outlen > 0 && nsc->ns_outptr[outlen - 1] == '\r')
+               outlen--;
+       } else {
+           nsc->ns_snoop_noend = 1;
+       }
+       if (outlen > 0 || nsc->ns_snoop_noend == 0) {
+#ifdef CYRUS_SASL
+           if (nsc->sasl_seclayer)
+               fprintf(stderr, "(sasl-encrypted) ");
+#endif /* CYRUS_SASL */
+#ifdef TLS_SUPPORT
+           if (nsc->tls_active)
+               fprintf(stderr, "(tls-encrypted) ");
+#endif /* TLS_SUPPORT */
+           fprintf(stderr, "=> ");
+           if (nsc->ns_snoop_cb)
+               nsc->ns_snoop_cb(nsc, nsc->ns_outptr, outlen);
+           else
+                fprintf(stderr, "%.*s\n", outlen, nsc->ns_outptr); 
+       } else {
+           nsc->ns_snoop_noend = 0;
+       }
+    }
+
     nsc->ns_outptr += rc;
     nsc->ns_outbuflen += rc;
 
@@ -745,6 +794,13 @@ netsec_flush(netsec_context *nsc, char **errstr)
     }
 #endif /* TLS_SUPPORT */
 
+    /*
+     * Small optimization
+     */
+
+    if (netoutlen == 0)
+       return OK;
+
     /*
      * If SASL security layers are in effect, run the data through
      * sasl_encode() first and then write it.
@@ -965,7 +1021,8 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
     int *outbufmax;
 #endif
 #ifdef OAUTH_SUPPORT
-    const char *xoauth_client_res;
+    unsigned char *xoauth_client_res;
+    size_t xoauth_client_res_len;
 #endif /* OAUTH_SUPPORT */
     int rc;
 
@@ -999,11 +1056,11 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
     }
 
 #ifdef OAUTH_SUPPORT
-    if (strcasecmp(nsc->sasl_mech, "XOAUTH2") == 0) {
+    if (nsc->sasl_mech && strcasecmp(nsc->sasl_mech, "XOAUTH2") == 0) {
        /*
         * This should be relatively straightforward, but requires some
         * help from the plugin.  Basically, if XOAUTH2 is a success,
-        * the plugin has to return success, but no output data.  If
+        * the callback has to return success, but no output data.  If
         * there is output data, it will be assumed that it is the JSON
         * error message.
         */
@@ -1015,19 +1072,46 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
 
        nsc->sasl_chosen_mech = getcpy(nsc->sasl_mech);
 
-       xoauth_client_res = mh_oauth_do_xoauth(nsc->ns_userid,
-                                              nsc->oauth_service,
-                                              nsc->ns_snoop ? stderr : NULL);
-
-       if (xoauth_client_res == NULL) {
-           netsec_err(errstr, "Internal error: mh_oauth_do_xoauth() "
-                      "returned NULL");
+       if (mh_oauth_do_xoauth(nsc->ns_userid, nsc->oauth_service,
+                              &xoauth_client_res, &xoauth_client_res_len,
+                              nsc->ns_snoop ? stderr : NULL) != OK) {
+           netsec_err(errstr, "Internal error: Unable to get OAuth2 "
+                      "bearer token");
            return NOTOK;
        }
 
-#if 0
-       rc = nsc->sasl_proto_cb(NETSEC_SASL_START, 
-#endif
+       rc = nsc->sasl_proto_cb(NETSEC_SASL_START, xoauth_client_res,
+                               xoauth_client_res_len, NULL, 0, errstr);
+       free(xoauth_client_res);
+
+       if (rc != OK)
+           return NOTOK;
+
+       /*
+        * Okay, we need to do a NETSEC_SASL_FINISH now.  If we return
+        * success, we indicate that with no output data.  But if we
+        * fail, then send a blank message and get the resulting
+        * error.
+        */
+
+       rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0, errstr);
+
+       if (rc != OK) {
+           /*
+            * We're going to assume the error here is a JSON response;
+            * we ignore it and send a blank message in response.  We should
+            * then get either an +OK or -ERR
+            */
+           free(errstr);
+           nsc->sasl_proto_cb(NETSEC_SASL_WRITE, NULL, 0, NULL, 0, NULL);
+           rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
+                                   errstr);
+           if (rc == 0) {
+               netsec_err(errstr, "Unexpected success after OAuth failure!");
+           }
+           return NOTOK;
+       }
+       return OK;
     }
 #endif /* OAUTH_SUPPORT */
 
@@ -1078,18 +1162,8 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
 
     nsc->sasl_chosen_mech = getcpy(chosen_mech);
 
-    if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, &outbuf,
-                          &outbuflen, errstr) != OK)
-       return NOTOK;
-
-    if (netsec_write(nsc, outbuf, outbuflen, errstr) != OK) {
-       free(outbuf);
-       return NOTOK;
-    }
-
-    free(outbuf);
-
-    if (netsec_flush(nsc, errstr) != OK)
+    if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, NULL, 0,
+                          errstr) != OK)
        return NOTOK;
 
     /*
@@ -1104,52 +1178,28 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
 
        if (nsc->sasl_proto_cb(NETSEC_SASL_READ, NULL, 0, &outbuf, &outbuflen,
                               errstr) != OK) {
-           if (nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, &outbuf,
-                                  &outbuflen, NULL) == OK) {
-               netsec_write(nsc, outbuf, outbuflen, NULL);
-               netsec_flush(nsc, NULL);
-               free(outbuf);
-           }
+           nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
            return NOTOK;
        }
 
        rc = sasl_client_step(nsc->sasl_conn, (char *) outbuf, outbuflen, NULL,
                              (const char **) &saslbuf, &saslbuflen);
 
-       free(outbuf);
+       if (outbuf)
+           free(outbuf);
 
        if (rc != SASL_OK && rc != SASL_CONTINUE) {
            netsec_err(errstr, "SASL client negotiation failed: %s",
                       sasl_errdetail(nsc->sasl_conn));
-           if (nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, &outbuf,
-                                  &outbuflen, NULL) == OK) {
-               netsec_write(nsc, outbuf, outbuflen, NULL);
-               netsec_flush(nsc, NULL);
-               free(outbuf);
-           }
+           nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
            return NOTOK;
        }
 
        if (nsc->sasl_proto_cb(NETSEC_SASL_WRITE, saslbuf, saslbuflen,
-                              &outbuf, &outbuflen, errstr) != OK) {
-           if (nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, &outbuf,
-                                  &outbuflen, NULL) == OK) {
-               netsec_write(nsc, outbuf, outbuflen, NULL);
-               netsec_flush(nsc, NULL);
-               free(outbuf);
-           }
+                              NULL, 0, errstr) != OK) {
+           nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
            return NOTOK;
        }
-
-       if (netsec_write(nsc, outbuf, outbuflen, errstr) != OK) {
-           free(outbuf);
-           return NOTOK;
-       }
-
-       free(outbuf);
-
-       if (netsec_flush(nsc, errstr) != OK)
-           return NOTOK;
     }
 
     /*
@@ -1455,7 +1505,7 @@ netsec_negotiate_tls(netsec_context *nsc, char **errstr)
  * Generate an (allocated) error string
  */
 
-static void
+void
 netsec_err(char **errstr, const char *fmt, ...)
 {
     va_list ap;