]> diplodocus.org Git - nmh/commitdiff
Shuffle some stuff around, change some prototypes, and modify the
authorKen Hornstein <kenh@pobox.com>
Wed, 21 Sep 2016 00:09:37 +0000 (20:09 -0400)
committerKen Hornstein <kenh@pobox.com>
Wed, 21 Sep 2016 00:09:37 +0000 (20:09 -0400)
oauth code a bit to fit our new structure.

h/netsec.h
h/oauth.h
mts/smtp/smtp.c
sbr/netsec.c
sbr/oauth.c
uip/popsbr.c

index ef0d521d2c491fe4c6fc199c54b3fad7c32700cf..5372714c9729ee8e142c2fa89dbfa061db6bb61a 100644 (file)
@@ -210,16 +210,17 @@ enum sasl_message_type {
  * outdatasize - Size of output data
  * errstr      - An error string to be returned (freed by caller).
  *
  * outdatasize - Size of output data
  * errstr      - An error string to be returned (freed by caller).
  *
+ * As a general note, plugins should perform their own I/O.  Buffers returned
+ * by NETSEC_SASL_READ should be allocated by the plugins and will be freed
+ * by the netsec package.  Error messages returned should be created by
+ * netsec_err().
+ *
  * Parameter interpretation based on mtype value:
  *
  * NETSEC_SASL_START   - Create a protocol message that starts SASL
  *                       authentication.  If an initial response is
  *                       supported, indata and indatasize will contain it.
  *                       Otherwise they will be set to NULL and 0.
  * Parameter interpretation based on mtype value:
  *
  * NETSEC_SASL_START   - Create a protocol message that starts SASL
  *                       authentication.  If an initial response is
  *                       supported, indata and indatasize will contain it.
  *                       Otherwise they will be set to NULL and 0.
- *                       The complete protocol message should be
- *                       stored in outdata/outdatasize, to be free()d
- *                       by the caller.  Alternatively, the plugin
- *                       can choose to send the data on their own.
  * NETSEC_SASL_READ    - Parse and decode a protocol message and extract
  *                       out the SASL payload data.  indata will be set
  *                       to NULL; the callback must read in the necessary
  * NETSEC_SASL_READ    - Parse and decode a protocol message and extract
  *                       out the SASL payload data.  indata will be set
  *                       to NULL; the callback must read in the necessary
@@ -228,10 +229,7 @@ enum sasl_message_type {
  *                       SASL message (again, must be free()d by the caller).
  * NETSEC_SASL_WRITE   - Generate a protocol message to send over the
  *                       network.  indata/indatasize will contain the
  *                       SASL message (again, must be free()d by the caller).
  * NETSEC_SASL_WRITE   - Generate a protocol message to send over the
  *                       network.  indata/indatasize will contain the
- *                       SASL payload data.  outdata/outdatasize should
- *                       contain the complete protocol message.  Alternatively
- *                       the plugin can write the data to the network
- *                       directly.
+ *                       SASL payload data.
  * NETSEC_SASL_FINISH  - Process the final SASL message exchange; at
  *                       this point SASL exchange should have completed
  *                       and we should get a message back from the server
  * NETSEC_SASL_FINISH  - Process the final SASL message exchange; at
  *                       this point SASL exchange should have completed
  *                       and we should get a message back from the server
@@ -244,11 +242,6 @@ enum sasl_message_type {
  * The callback should return OK on success, NOTOK on failure.  Depending
  * at the point of the authentication exchange, the callback may be asked
  * to generate a cancel message.
  * The callback should return OK on success, NOTOK on failure.  Depending
  * at the point of the authentication exchange, the callback may be asked
  * to generate a cancel message.
- *
- * Some higher-level notes in terms of protocol management:
- *
- * Any data returned in outdata should consist of allocated data that
- * the sasl routines is expected to free.
  */
 
 typedef int (*netsec_sasl_callback)(enum sasl_message_type mtype,
  */
 
 typedef int (*netsec_sasl_callback)(enum sasl_message_type mtype,
index 274ca9de4d06675966ab2231a9d210cc594eb609..0278cae7c3890a7823e6b148550dcb926ccbff37 100644 (file)
--- a/h/oauth.h
+++ b/h/oauth.h
@@ -105,14 +105,18 @@ struct mh_oauth_service_info {
  * Do the complete dance for XOAUTH2 as used by POP3 and SMTP.
  *
  * Load tokens for svc from disk, refresh if necessary, and return the
  * Do the complete dance for XOAUTH2 as used by POP3 and SMTP.
  *
  * Load tokens for svc from disk, refresh if necessary, and return the
- * base64-encoded client response.
+ * client response in client_response and client_response_len.
  *
  * If refreshing, writes freshened tokens to disk.
  *
  * Exits via adios on any error.
  *
  * If refreshing, writes freshened tokens to disk.
  *
  * Exits via adios on any error.
+ *
+ * Always returns OK for now, but in the future could return NOTOK on error.
  */
  */
-char *
-mh_oauth_do_xoauth(const char *user, const char *svc, FILE *log);
+
+int
+mh_oauth_do_xoauth(const char *user, const char *svc, unsigned char **oauth_res,
+                  size_t *oauth_res_len, FILE *log);
 
 /*
  * Allocate and initialize a new OAuth context.
 
 /*
  * Allocate and initialize a new OAuth context.
index 79c1e79b4d0da2b5850cab8899c1a93be27edf37..dff7628a6ce6ee1a972a71c4d0b2aab45a310f9a 100644 (file)
@@ -1160,7 +1160,7 @@ sm_auth_xoauth2(const char *user, const char *oauth_svc, int snoop)
     const char *xoauth_client_res;
     int status;
 
     const char *xoauth_client_res;
     int status;
 
-#ifdef OAUTH_SUPPORT
+#if 0
     xoauth_client_res = mh_oauth_do_xoauth(user, oauth_svc,
                                           snoop ? stderr : NULL);
 
     xoauth_client_res = mh_oauth_do_xoauth(user, oauth_svc,
                                           snoop ? stderr : NULL);
 
index abdcaee85008cac7eb5c26cb0c9f242ae461c97d..c5dfef01bbdca10311cf6ca4f507fb2f483ddfab 100644 (file)
@@ -974,7 +974,8 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
     int *outbufmax;
 #endif
 #ifdef OAUTH_SUPPORT
     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;
 
 #endif /* OAUTH_SUPPORT */
     int rc;
 
@@ -1012,7 +1013,7 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
        /*
         * This should be relatively straightforward, but requires some
         * help from the plugin.  Basically, if XOAUTH2 is a success,
        /*
         * 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.
         */
         * there is output data, it will be assumed that it is the JSON
         * error message.
         */
@@ -1024,19 +1025,45 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
 
        nsc->sasl_chosen_mech = getcpy(nsc->sasl_mech);
 
 
        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;
        }
 
            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;
+       }
     }
 #endif /* OAUTH_SUPPORT */
 
     }
 #endif /* OAUTH_SUPPORT */
 
@@ -1087,21 +1114,10 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
 
     nsc->sasl_chosen_mech = getcpy(chosen_mech);
 
 
     nsc->sasl_chosen_mech = getcpy(chosen_mech);
 
-    if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, &outbuf,
-                          &outbuflen, errstr) != OK)
+    if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, NULL, 0,
+                          errstr) != OK)
        return NOTOK;
 
        return NOTOK;
 
-    if (outbuflen > 0) {
-       if (netsec_write(nsc, outbuf, outbuflen, errstr) != OK) {
-           free(outbuf);
-           return NOTOK;
-       }
-       free(outbuf);
-       if (netsec_flush(nsc, errstr) != OK)
-           return NOTOK;
-    }
-
-
     /*
      * We've written out our first message; enter in the step loop
      */
     /*
      * We've written out our first message; enter in the step loop
      */
@@ -1114,14 +1130,7 @@ 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_READ, NULL, 0, &outbuf, &outbuflen,
                               errstr) != OK) {
-           if (nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, &outbuf,
-                                  &outbuflen, NULL) == OK) {
-               if (outbuflen > 0) {
-                   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;
        }
 
            return NOTOK;
        }
 
@@ -1134,39 +1143,15 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
        if (rc != SASL_OK && rc != SASL_CONTINUE) {
            netsec_err(errstr, "SASL client negotiation failed: %s",
                       sasl_errdetail(nsc->sasl_conn));
        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) {
-               if (outbuflen > 0) {
-                   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,
            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) {
-               if (outbuflen > 0) {
-                   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;
        }
            return NOTOK;
        }
-
-       if (outbuflen > 0) {
-           if (netsec_write(nsc, outbuf, outbuflen, errstr) != OK) {
-               free(outbuf);
-               return NOTOK;
-           }
-           free(outbuf);
-           if (netsec_flush(nsc, errstr) != OK)
-               return NOTOK;
-       }
     }
 
     /*
     }
 
     /*
index ae745fcf89b190831eec4a56e3c80285ee00bf55..85fe7146e768f59920beedfd6ef3ceadba78ea38 100644 (file)
@@ -127,17 +127,16 @@ static boolean get_json_strings(const char *, size_t, FILE *, ...);
 static boolean make_query_url(char *, size_t, CURL *, const char *, ...);
 static boolean post(struct curl_ctx *, const char *, const char *);
 
 static boolean make_query_url(char *, size_t, CURL *, const char *, ...);
 static boolean post(struct curl_ctx *, const char *, const char *);
 
-char *
-mh_oauth_do_xoauth(const char *user, const char *svc, FILE *log)
+int
+mh_oauth_do_xoauth(const char *user, const char *svc, unsigned char **oauth_res,
+                  size_t *oauth_res_len, FILE *log)
 {
     mh_oauth_ctx *ctx;
     mh_oauth_cred *cred;
     char *fn;
     int failed_to_lock = 0;
     FILE *fp;
 {
     mh_oauth_ctx *ctx;
     mh_oauth_cred *cred;
     char *fn;
     int failed_to_lock = 0;
     FILE *fp;
-    size_t client_res_len;
     char *client_res;
     char *client_res;
-    char *client_res_b64;
 
     if (!mh_oauth_new (&ctx, svc)) adios(NULL, mh_oauth_get_err_string(ctx));
 
 
     if (!mh_oauth_new (&ctx, svc)) adios(NULL, mh_oauth_get_err_string(ctx));
 
@@ -183,18 +182,14 @@ mh_oauth_do_xoauth(const char *user, const char *svc, FILE *log)
     free(fn);
 
     /* XXX writeBase64raw modifies the source buffer!  make a copy */
     free(fn);
 
     /* XXX writeBase64raw modifies the source buffer!  make a copy */
-    client_res = getcpy(mh_oauth_sasl_client_response(&client_res_len, user,
+    client_res = getcpy(mh_oauth_sasl_client_response(oauth_res_len, user,
                                                       cred));
     mh_oauth_cred_free(cred);
     mh_oauth_free(ctx);
                                                       cred));
     mh_oauth_cred_free(cred);
     mh_oauth_free(ctx);
-    client_res_b64 = mh_xmalloc(((((client_res_len) + 2) / 3 ) * 4) + 1);
-    if (writeBase64raw((unsigned char *)client_res, client_res_len,
-                       (unsigned char *)client_res_b64) != OK) {
-        adios(NULL, "base64 encoding of XOAUTH2 client response failed");
-    }
-    free(client_res);
 
 
-    return client_res_b64;
+    *oauth_res = (unsigned char *) client_res;
+
+    return OK;
 }
 
 static boolean
 }
 
 static boolean
index 884fea4f1861f7bb2c51fa543c66ce7dd64c43e4..56765916913088212950573dffc9c62027574ce8 100644 (file)
@@ -682,7 +682,7 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
 
        /*
         * We should get one line back, with our base64 data.  Decode that
 
        /*
         * We should get one line back, with our base64 data.  Decode that
-        * and feed it back in.
+        * and feed it back into the SASL library.
         */
     case NETSEC_SASL_READ:
        line = netsec_readline(nsc, &len, errstr);
         */
     case NETSEC_SASL_READ:
        line = netsec_readline(nsc, &len, errstr);
@@ -711,20 +711,21 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
 
     case NETSEC_SASL_WRITE:
        if (indatalen == 0) {
 
     case NETSEC_SASL_WRITE:
        if (indatalen == 0) {
-           *outdata = (unsigned char *) getcpy("\r\n");
-           *outdatalen = strlen((char *) *outdata);
+           rc = netsec_printf(nsc, errstr, "\r\n");
        } else {
            unsigned char *b64data;
        } else {
            unsigned char *b64data;
-           b64data = mh_xmalloc(BASE64SIZE(indatalen) + 3);
+           b64data = mh_xmalloc(BASE64SIZE(indatalen));
            writeBase64raw(indata, indatalen, b64data);
            writeBase64raw(indata, indatalen, b64data);
-           len = strlen((char *) b64data);
-           b64data[len++] = '\r';
-           b64data[len++] = '\n';
-           b64data[len++] = '\0';
-           *outdata = b64data;
-           *outdatalen = len - 1;
+           rc = netsec_printf(nsc, errstr, "%s\r\n", b64data);
+           free(b64data);
        }
 
        }
 
+       if (rc != OK)
+           return NOTOK;
+
+       if (netsec_flush(nsc, errstr) != OK)
+           return NOTOK;
+
        return OK;
        break;
 
        return OK;
        break;
 
@@ -746,11 +747,18 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
     /*
      * Cancel the SASL exchange in the middle of the commands; for
      * POP, that's a single "*".
     /*
      * Cancel the SASL exchange in the middle of the commands; for
      * POP, that's a single "*".
+     *
+     * It's unclear to me if I should be returning errors up; I finally
+     * decided the answer should be "yes", and if the upper layer wants to
+     * ignore them that's their choice.
      */
 
     case NETSEC_SASL_CANCEL:
      */
 
     case NETSEC_SASL_CANCEL:
-       *outdata = (unsigned char *) getcpy("*\r\n");
-       *outdatalen = strlen((char *) *outdata);
+       rc = netsec_printf(nsc, errstr, "*\r\n");
+       if (rc == OK)
+           rc = netsec_flush(nsc, errstr);
+       if (rc != OK)
+           return NOTOK;
        break;
     }
 
        break;
     }