]> diplodocus.org Git - nmh/commitdiff
Retrieve appropriate profile entries and pass them to post(8).
authorKen Hornstein <kenh@pobox.com>
Sat, 20 Aug 2016 05:18:13 +0000 (01:18 -0400)
committerKen Hornstein <kenh@pobox.com>
Sat, 20 Aug 2016 05:18:13 +0000 (01:18 -0400)
Not quite working yet.

Makefile.am
h/oauth.h
mts/smtp/smtp.c
sbr/oauth.c
sbr/oauth_prof.c [new file with mode: 0644]
uip/post.c
uip/sendsbr.c

index 9b1d2650b4c129f176ba730909dab7dff4d9e451..dbcd7c32c807a0187cb0a00a9445bfee4fafdefd 100644 (file)
@@ -325,11 +325,11 @@ uip_burst_LDADD = $(LDADD) $(ICONVLIB) $(POSTLINK)
 
 uip_comp_SOURCES = uip/comp.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c
 
 uip_comp_SOURCES = uip/comp.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c
-uip_comp_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(CURLLIB) $(POSTLINK)
+uip_comp_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_dist_SOURCES = uip/dist.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c uip/forwsbr.c
 
 uip_dist_SOURCES = uip/dist.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c uip/forwsbr.c
-uip_dist_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(CURLLIB) $(POSTLINK)
+uip_dist_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_flist_SOURCES = uip/flist.c
 uip_flist_LDADD = $(LDADD) $(POSTLINK)
 
 uip_flist_SOURCES = uip/flist.c
 uip_flist_LDADD = $(LDADD) $(POSTLINK)
@@ -339,7 +339,7 @@ uip_folder_LDADD = $(LDADD) $(POSTLINK)
 
 uip_forw_SOURCES = uip/forw.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c uip/forwsbr.c
 
 uip_forw_SOURCES = uip/forw.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c uip/forwsbr.c
-uip_forw_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(CURLLIB) $(POSTLINK)
+uip_forw_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_inc_SOURCES = uip/inc.c uip/scansbr.c uip/dropsbr.c uip/popsbr.c
 uip_inc_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(SASLLIB) $(CURLLIB) $(POSTLINK)
 
 uip_inc_SOURCES = uip/inc.c uip/scansbr.c uip/dropsbr.c uip/popsbr.c
 uip_inc_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(SASLLIB) $(CURLLIB) $(POSTLINK)
@@ -408,7 +408,7 @@ uip_refile_LDADD = $(LDADD) $(POSTLINK)
 
 uip_repl_SOURCES = uip/repl.c uip/replsbr.c uip/whatnowproc.c uip/whatnowsbr.c \
                   uip/sendsbr.c uip/annosbr.c uip/distsbr.c
 
 uip_repl_SOURCES = uip/repl.c uip/replsbr.c uip/whatnowproc.c uip/whatnowsbr.c \
                   uip/sendsbr.c uip/annosbr.c uip/distsbr.c
-uip_repl_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(CURLLIB) $(POSTLINK)
+uip_repl_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_rmf_SOURCES = uip/rmf.c
 uip_rmf_LDADD = $(LDADD) $(POSTLINK)
 
 uip_rmf_SOURCES = uip/rmf.c
 uip_rmf_LDADD = $(LDADD) $(POSTLINK)
@@ -421,7 +421,7 @@ uip_scan_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_send_SOURCES = uip/send.c uip/sendsbr.c uip/annosbr.c \
                   uip/distsbr.c
 
 uip_send_SOURCES = uip/send.c uip/sendsbr.c uip/annosbr.c \
                   uip/distsbr.c
-uip_send_LDADD = $(LDADD) $(TERMLIB) $(CURLLIB) $(ICONVLIB) $(POSTLINK)
+uip_send_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_show_SOURCES = uip/show.c uip/mhlsbr.c
 uip_show_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_show_SOURCES = uip/show.c uip/mhlsbr.c
 uip_show_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
@@ -431,7 +431,7 @@ uip_sortm_LDADD = $(LDADD) $(POSTLINK)
 
 uip_whatnow_SOURCES = uip/whatnow.c uip/whatnowsbr.c uip/sendsbr.c \
                      uip/annosbr.c uip/distsbr.c
 
 uip_whatnow_SOURCES = uip/whatnow.c uip/whatnowsbr.c uip/sendsbr.c \
                      uip/annosbr.c uip/distsbr.c
-uip_whatnow_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(CURLLIB) $(ICONVLIB) \
+uip_whatnow_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) \
                    $(POSTLINK)
 
 uip_whom_SOURCES = uip/whom.c uip/distsbr.c
                    $(POSTLINK)
 
 uip_whom_SOURCES = uip/whom.c uip/distsbr.c
@@ -463,7 +463,8 @@ uip_mkstemp_SOURCES = uip/mkstemp.c
 uip_mkstemp_LDADD = $(LDADD) $(POSTLINK)
 
 uip_post_SOURCES = uip/post.c uip/aliasbr.c
 uip_mkstemp_LDADD = $(LDADD) $(POSTLINK)
 
 uip_post_SOURCES = uip/post.c uip/aliasbr.c
-uip_post_LDADD = mts/libmts.a $(LDADD) $(SASLLIB) $(TLSLIB) $(POSTLINK)
+uip_post_LDADD = mts/libmts.a $(LDADD) $(SASLLIB) $(CURLLIB) $(TLSLIB) \
+                $(POSTLINK)
 
 uip_rcvdist_SOURCES = uip/rcvdist.c uip/distsbr.c
 uip_rcvdist_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_rcvdist_SOURCES = uip/rcvdist.c uip/distsbr.c
 uip_rcvdist_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
@@ -482,7 +483,7 @@ uip_slocal_LDADD = $(LDADD) $(NDBM_LIBS) $(POSTLINK)
 
 uip_viamail_SOURCES = uip/viamail.c uip/mhmisc.c uip/sendsbr.c \
                      uip/annosbr.c uip/distsbr.c
 
 uip_viamail_SOURCES = uip/viamail.c uip/mhmisc.c uip/sendsbr.c \
                      uip/annosbr.c uip/distsbr.c
-uip_viamail_LDADD = $(LDADD) $(TERMLIB) $(CURLLIB) $(ICONVLIB) $(POSTLINK)
+uip_viamail_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 ##
 ## Other program definitions
 
 ##
 ## Other program definitions
@@ -627,7 +628,7 @@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/arglist.c \
                      sbr/trimcpy.c sbr/unquote.c \
                      sbr/uprf.c sbr/vfgets.c \
                      sbr/mf.c sbr/utils.c sbr/ctype-checked.c \
                      sbr/trimcpy.c sbr/unquote.c \
                      sbr/uprf.c sbr/vfgets.c \
                      sbr/mf.c sbr/utils.c sbr/ctype-checked.c \
-                     sbr/m_mktemp.c sbr/vector.c sbr/oauth.c \
+                     sbr/m_mktemp.c sbr/vector.c sbr/oauth.c sbr/oauth_prof.c \
                      config/config.c config/version.c \
                      thirdparty/jsmn/jsmn.c
 
                      config/config.c config/version.c \
                      thirdparty/jsmn/jsmn.c
 
index 0abaaa34907846f1f7dd8cb559cf2104780a4ea0..d1c9c2202c7a6cf05ff29076082fb44f0ee16d0c 100644 (file)
--- a/h/oauth.h
+++ b/h/oauth.h
@@ -75,6 +75,32 @@ typedef struct mh_oauth_ctx mh_oauth_ctx;
 
 typedef struct mh_oauth_cred mh_oauth_cred;
 
 
 typedef struct mh_oauth_cred mh_oauth_cred;
 
+typedef struct mh_oauth_service_info mh_oauth_service_info;
+
+struct mh_oauth_service_info {
+    /* Name of service, so we can search static internal services array
+     * and for determining default credential file name. */
+    char *name;
+
+    /* Human-readable name of the service; in mh_oauth_ctx::svc this is not
+     * another buffer to free, but a pointer to either static SERVICE data
+     * (below) or to the name field. */
+    char *display_name;
+
+    /* [1] 2.2 Client Identifier, 2.3.1 Client Password */
+    char *client_id;
+    /* [1] 2.3.1 Client Password */
+    char *client_secret;
+    /* [1] 3.1 Authorization Endpoint */
+    char *auth_endpoint;
+    /* [1] 3.1.2 Redirection Endpoint */
+    char *redirect_uri;
+    /* [1] 3.2 Token Endpoint */
+    char *token_endpoint;
+    /* [1] 3.3 Access Token Scope */
+    char *scope;
+};
+
 /*
  * Do the complete dance for XOAUTH2 as used by POP3 and SMTP.
  *
 /*
  * Do the complete dance for XOAUTH2 as used by POP3 and SMTP.
  *
@@ -223,3 +249,14 @@ mh_oauth_cred_load(FILE *fp, mh_oauth_ctx *ctx, const char *user);
 const char *
 mh_oauth_sasl_client_response(size_t *res_len,
                               const char *user, const mh_oauth_cred *cred);
 const char *
 mh_oauth_sasl_client_response(size_t *res_len,
                               const char *user, const mh_oauth_cred *cred);
+
+/*
+ * Retrieve the various entries for the OAuth mechanism
+ */
+
+boolean 
+mh_oauth_get_service_info(const char *svc_name, mh_oauth_service_info *svcinfo,
+                         char *errbuf, size_t errbuflen);
+
+char *
+mh_oauth_node_name_for_svc(const char *entry, const char *svc_name);
index 8a78dea5700cca606776ac5cfc916e217027220c..75e59f6f57d7c36a22a3dd96a984a2a88d426821 100644 (file)
@@ -11,6 +11,7 @@
 #include <h/mts.h>
 #include <h/signals.h>
 #include <h/utils.h>
 #include <h/mts.h>
 #include <h/signals.h>
 #include <h/utils.h>
+#include <h/oauth.h>
 
 #ifdef CYRUS_SASL
 #include <sasl/sasl.h>
 
 #ifdef CYRUS_SASL
 #include <sasl/sasl.h>
@@ -174,7 +175,7 @@ static int sm_fputs(char *);
 static int sm_fputc(int);
 static void sm_fflush(void);
 static int sm_fgets(char *, int, FILE *);
 static int sm_fputc(int);
 static void sm_fflush(void);
 static int sm_fgets(char *, int, FILE *);
-static int sm_auth_xoauth2(const char *);
+static int sm_auth_xoauth2(const char *, const char *, int);
 
 #ifdef CYRUS_SASL
 /*
 
 #ifdef CYRUS_SASL
 /*
@@ -187,12 +188,12 @@ static int sm_auth_sasl(char *, int, char *, char *);
 int
 sm_init (char *client, char *server, char *port, int watch, int verbose,
          int debug, int sasl, int saslssf, char *saslmech, char *user,
 int
 sm_init (char *client, char *server, char *port, int watch, int verbose,
          int debug, int sasl, int saslssf, char *saslmech, char *user,
-         const char *xoauth_client_res, int tls)
+         const char *oauth_svc, int tls)
 {
     if (sm_mts == MTS_SMTP)
        return smtp_init (client, server, port, watch, verbose,
                          debug, sasl, saslssf, saslmech, user,
 {
     if (sm_mts == MTS_SMTP)
        return smtp_init (client, server, port, watch, verbose,
                          debug, sasl, saslssf, saslmech, user,
-                          xoauth_client_res, tls);
+                          oauth_svc, tls);
     else
        return sendmail_init (client, server, watch, verbose,
                               debug, sasl, saslssf, saslmech, user);
     else
        return sendmail_init (client, server, watch, verbose,
                               debug, sasl, saslssf, saslmech, user);
@@ -202,7 +203,7 @@ static int
 smtp_init (char *client, char *server, char *port, int watch, int verbose,
           int debug,
            int sasl, int saslssf, char *saslmech, char *user,
 smtp_init (char *client, char *server, char *port, int watch, int verbose,
           int debug,
            int sasl, int saslssf, char *saslmech, char *user,
-           const char *xoauth_client_res, int tls)
+           const char *oauth_svc, int tls)
 {
     int result, sd1, sd2;
 #ifndef CYRUS_SASL
 {
     int result, sd1, sd2;
 #ifndef CYRUS_SASL
@@ -380,7 +381,7 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
 
         /* Don't call sm_auth_sasl() for XAUTH2 with -sasl.  Instead, call
            sm_auth_xoauth2() below. */
 
         /* Don't call sm_auth_sasl() for XAUTH2 with -sasl.  Instead, call
            sm_auth_xoauth2() below. */
-       if (xoauth_client_res == NULL  &&
+       if (oauth_svc == NULL  &&
             sm_auth_sasl(user, saslssf, saslmech ? saslmech : server_mechs,
                         server) != RP_OK) {
            sm_end(NOTOK);
             sm_auth_sasl(user, saslssf, saslmech ? saslmech : server_mechs,
                         server) != RP_OK) {
            sm_end(NOTOK);
@@ -389,14 +390,14 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
     }
 #endif /* CYRUS_SASL */
 
     }
 #endif /* CYRUS_SASL */
 
-    if (xoauth_client_res != NULL) {
+    if (oauth_svc != NULL) {
         char *server_mechs;
        if ((server_mechs = EHLOset("AUTH")) == NULL
             || stringdex("XOAUTH2", server_mechs) == -1) {
            sm_end(NOTOK);
            return sm_ierror("SMTP server does not support SASL XOAUTH2");
        }
         char *server_mechs;
        if ((server_mechs = EHLOset("AUTH")) == NULL
             || stringdex("XOAUTH2", server_mechs) == -1) {
            sm_end(NOTOK);
            return sm_ierror("SMTP server does not support SASL XOAUTH2");
        }
-       if (sm_auth_xoauth2(xoauth_client_res) != RP_OK) {
+       if (sm_auth_xoauth2(user, oauth_svc, debug) != RP_OK) {
            sm_end(NOTOK);
            return NOTOK;
        }
            sm_end(NOTOK);
            return NOTOK;
        }
@@ -1154,9 +1155,18 @@ sm_get_pass(sasl_conn_t *conn, void *context, int id,
 
 /* https://developers.google.com/gmail/xoauth2_protocol */
 static int
 
 /* https://developers.google.com/gmail/xoauth2_protocol */
 static int
-sm_auth_xoauth2(const char *client_res)
+sm_auth_xoauth2(const char *user, const char *oauth_svc, int snoop)
 {
 {
-    int status = smtalk(SM_AUTH, "AUTH XOAUTH2 %s", client_res);
+    const char *xoauth_client_res;
+    int status;
+
+    xoauth_client_res = mh_oauth_do_xoauth(user, oauth_svc,
+                                          snoop ? stderr : NULL);
+
+    if (xoauth_client_res == NULL)
+       return sm_ierror("Internal error: oauth_do_xoauth() returned NULL");
+
+    status = smtalk(SM_AUTH, "AUTH XOAUTH2 %s", xoauth_client_res);
     if (status == 235) {
         /* It worked! */
         return RP_OK;
     if (status == 235) {
         /* It worked! */
         return RP_OK;
index b3e47a938972dd0a8ade20aa5a49bf767d49f7b4..e86aefe42def455081a68ec9a0023bff897dfde3 100644 (file)
  */
 #define URL_MAX 8192
 
  */
 #define URL_MAX 8192
 
-struct service_info {
-    /* Name of service, so we can search static SERVICES (below) and for
-     * determining default credential file name. */
-    char *name;
-
-    /* Human-readable name of the service; in mh_oauth_ctx::svc this is not
-     * another buffer to free, but a pointer to either static SERVICE data
-     * (below) or to the name field. */
-    char *display_name;
-
-    /* [1] 2.2 Client Identifier, 2.3.1 Client Password */
-    char *client_id;
-    /* [1] 2.3.1 Client Password */
-    char *client_secret;
-    /* [1] 3.1 Authorization Endpoint */
-    char *auth_endpoint;
-    /* [1] 3.1.2 Redirection Endpoint */
-    char *redirect_uri;
-    /* [1] 3.2 Token Endpoint */
-    char *token_endpoint;
-    /* [1] 3.3 Access Token Scope */
-    char *scope;
-};
-
-static const struct service_info SERVICES[] = {
-    /* https://developers.google.com/accounts/docs/OAuth2InstalledApp */
-    {
-        /* name */ "gmail",
-        /* display_name */ "Gmail",
-
-        /* client_id */ "91584523849-8lv9kgp1rvp8ahta6fa4b125tn2polcg.apps.googleusercontent.com",
-        /* client_secret */ "Ua8sX34xyv7hVrKM-U70dKI6",
-
-        /* auth_endpoint */ "https://accounts.google.com/o/oauth2/auth",
-        /* redirect_uri */ "urn:ietf:wg:oauth:2.0:oob",
-        /* token_endpoint */ "https://accounts.google.com/o/oauth2/token",
-        /* scope */ "https://mail.google.com/"
-    }
-};
-
 struct mh_oauth_cred {
     mh_oauth_ctx *ctx;
 
 struct mh_oauth_cred {
     mh_oauth_ctx *ctx;
 
@@ -114,7 +74,7 @@ struct mh_oauth_cred {
 };
 
 struct mh_oauth_ctx {
 };
 
 struct mh_oauth_ctx {
-    struct service_info svc;
+    struct mh_oauth_service_info svc;
     CURL *curl;
     FILE *log;
 
     CURL *curl;
     FILE *log;
 
@@ -283,78 +243,6 @@ set_err_http(mh_oauth_ctx *ctx, const struct curl_ctx *curl_ctx)
     free(error);
 }
 
     free(error);
 }
 
-/* Copy service info so we don't have to free it only sometimes. */
-static void
-copy_svc(struct service_info *to, const struct service_info *from)
-{
-    to->display_name = from->display_name;
-#define copy(_field_) to->_field_ = getcpy(from->_field_)
-    copy(name);
-    copy(scope);
-    copy(client_id);
-    copy(client_secret);
-    copy(auth_endpoint);
-    copy(token_endpoint);
-    copy(redirect_uri);
-#undef copy
-}
-
-/* Return profile component node name for a service parameter. */
-static char *
-node_name_for_svc(const char *base_name, const char *svc)
-{
-    char *result = mh_xmalloc(sizeof "oauth-" - 1
-                              + strlen(svc)
-                              + 1            /* '-' */
-                              + strlen(base_name)
-                              + 1            /* '\0' */);
-    sprintf(result, "oauth-%s-%s", svc, base_name);
-    /* TODO: s/_/-/g ? */
-    return result;
-}
-
-/* Update one service_info field if overridden in profile. */
-static void
-update_svc_field(char **field, const char *base_name, const char *svc)
-{
-    char *name = node_name_for_svc(base_name, svc);
-    const char *value = context_find(name);
-    if (value != NULL) {
-        free(*field);
-        *field = getcpy(value);
-    }
-    free(name);
-}
-
-/* Update all service_info fields that are overridden in profile. */
-static boolean
-update_svc(struct service_info *svc, const char *svc_name, mh_oauth_ctx *ctx)
-{
-#define update(name)                                                    \
-    update_svc_field(&svc->name, #name, svc_name);                       \
-    if (svc->name == NULL) {                                             \
-        set_err_details(ctx, MH_OAUTH_BAD_PROFILE, #name " is missing"); \
-        return FALSE;                                                    \
-    }
-    update(scope);
-    update(client_id);
-    update(client_secret);
-    update(auth_endpoint);
-    update(token_endpoint);
-    update(redirect_uri);
-#undef update
-
-    if (svc->name == NULL) {
-        svc->name = getcpy(svc_name);
-    }
-
-    if (svc->display_name == NULL) {
-        svc->display_name = svc->name;
-    }
-
-    return TRUE;
-}
-
 static char *
 make_user_agent()
 {
 static char *
 make_user_agent()
 {
@@ -373,26 +261,15 @@ boolean
 mh_oauth_new(mh_oauth_ctx **result, const char *svc_name)
 {
     mh_oauth_ctx *ctx = *result = mh_xmalloc(sizeof *ctx);
 mh_oauth_new(mh_oauth_ctx **result, const char *svc_name)
 {
     mh_oauth_ctx *ctx = *result = mh_xmalloc(sizeof *ctx);
-    size_t i;
 
     ctx->curl = NULL;
 
     ctx->log = NULL;
     ctx->cred_fn = ctx->sasl_client_res = ctx->err_formatted = NULL;
 
 
     ctx->curl = NULL;
 
     ctx->log = NULL;
     ctx->cred_fn = ctx->sasl_client_res = ctx->err_formatted = NULL;
 
-    ctx->svc.name = ctx->svc.display_name = NULL;
-    ctx->svc.scope = ctx->svc.client_id = NULL;
-    ctx->svc.client_secret = ctx->svc.auth_endpoint = NULL;
-    ctx->svc.token_endpoint = ctx->svc.redirect_uri = NULL;
-
-    for (i = 0; i < sizeof SERVICES / sizeof SERVICES[0]; i++) {
-        if (strcmp(SERVICES[i].name, svc_name) == 0) {
-            copy_svc(&ctx->svc, &SERVICES[i]);
-            break;
-        }
-    }
-
-    if (!update_svc(&ctx->svc, svc_name, ctx)) {
+    if (!mh_oauth_get_service_info(svc_name, &ctx->svc, ctx->err_buf,
+                                  sizeof(ctx->err_buf))) {
+       set_err_details(ctx, MH_OAUTH_BAD_PROFILE, ctx->err_buf);
         return FALSE;
     }
 
         return FALSE;
     }
 
@@ -698,7 +575,7 @@ mh_oauth_cred_fn(mh_oauth_ctx *ctx)
     char *result, *result_if_allocated;
     const char *svc = ctx->svc.name;
 
     char *result, *result_if_allocated;
     const char *svc = ctx->svc.name;
 
-    char *component = node_name_for_svc("credential-file", svc);
+    char *component = mh_oauth_node_name_for_svc("credential-file", svc);
     result = context_find(component);
     free(component);
 
     result = context_find(component);
     free(component);
 
diff --git a/sbr/oauth_prof.c b/sbr/oauth_prof.c
new file mode 100644 (file)
index 0000000..4f9e2a2
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * This code is Copyright (c) 2014, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ */
+
+#include <h/mh.h>
+
+#ifdef OAUTH_SUPPORT
+
+#include <sys/stat.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <h/oauth.h>
+#include <h/utils.h>
+
+static const struct mh_oauth_service_info SERVICES[] = {
+    /* https://developers.google.com/accounts/docs/OAuth2InstalledApp */
+    {
+        /* name */ "gmail",
+        /* display_name */ "Gmail",
+
+        /* client_id */ "91584523849-8lv9kgp1rvp8ahta6fa4b125tn2polcg.apps.googleusercontent.com",
+        /* client_secret */ "Ua8sX34xyv7hVrKM-U70dKI6",
+
+        /* auth_endpoint */ "https://accounts.google.com/o/oauth2/auth",
+        /* redirect_uri */ "urn:ietf:wg:oauth:2.0:oob",
+        /* token_endpoint */ "https://accounts.google.com/o/oauth2/token",
+        /* scope */ "https://mail.google.com/"
+    }
+};
+
+/* Copy service info so we don't have to free it only sometimes. */
+static void
+copy_svc(mh_oauth_service_info *to, const mh_oauth_service_info *from)
+{
+    to->display_name = from->display_name;
+#define copy(_field_) to->_field_ = getcpy(from->_field_)
+    copy(name);
+    copy(scope);
+    copy(client_id);
+    copy(client_secret);
+    copy(auth_endpoint);
+    copy(token_endpoint);
+    copy(redirect_uri);
+#undef copy
+}
+
+/* Return profile component node name for a service parameter. */
+char *
+mh_oauth_node_name_for_svc(const char *base_name, const char *svc)
+{
+    char *result = mh_xmalloc(sizeof "oauth-" - 1
+                              + strlen(svc)
+                              + 1            /* '-' */
+                              + strlen(base_name)
+                              + 1            /* '\0' */);
+    sprintf(result, "oauth-%s-%s", svc, base_name);
+    /* TODO: s/_/-/g ? */
+    return result;
+}
+
+/* Update one service_info field if overridden in profile. */
+static void
+update_svc_field(char **field, const char *base_name, const char *svc)
+{
+    char *name = mh_oauth_node_name_for_svc(base_name, svc);
+    const char *value = context_find(name);
+    if (value != NULL) {
+        free(*field);
+        *field = getcpy(value);
+    }
+    free(name);
+}
+
+/* Update all service_info fields that are overridden in profile. */
+static boolean
+update_svc(mh_oauth_service_info *svc, const char *svc_name, char *errbuf,
+          size_t errbuflen)
+{
+#define update(name)                                                    \
+    update_svc_field(&svc->name, #name, svc_name);                       \
+    if (svc->name == NULL) {                                             \
+       snprintf(errbuf, errbuflen, "%s", #name " is missing");          \
+       errbuf[errbuflen - 1] = '\0';                                    \
+        return FALSE;                                                    \
+    }
+    update(scope);
+    update(client_id);
+    update(client_secret);
+    update(auth_endpoint);
+    update(token_endpoint);
+    update(redirect_uri);
+#undef update
+
+    if (svc->name == NULL) {
+        svc->name = getcpy(svc_name);
+    }
+
+    if (svc->display_name == NULL) {
+        svc->display_name = svc->name;
+    }
+
+    return TRUE;
+}
+
+boolean
+mh_oauth_get_service_info(const char *svc_name, mh_oauth_service_info *svcinfo,
+                         char *errbuf, size_t errbuflen)
+{
+    int i;
+
+    svcinfo->name = svcinfo->display_name = NULL;
+    svcinfo->scope = svcinfo->client_id = NULL;
+    svcinfo->client_secret = svcinfo->auth_endpoint = NULL;
+    svcinfo->token_endpoint = svcinfo->redirect_uri = NULL;
+
+    for (i = 0; i < (int) (sizeof SERVICES / sizeof SERVICES[0]); i++) {
+        if (strcmp(SERVICES[i].name, svc_name) == 0) {
+            copy_svc(svcinfo, &SERVICES[i]);
+            break;
+        }
+    }
+
+    if (!update_svc(svcinfo, svc_name, errbuf, errbuflen)) {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+#endif
index 0660f17be9267cfa87f890a40bcaf7b22a0cced1..43110f3678889280b91246974b5187474cac558e 100644 (file)
@@ -40,7 +40,7 @@
 #ifndef OAUTH_SUPPORT
 # define OAUTHminc(a)  (a)
 #else /* OAUTH_SUPPORT */
 #ifndef OAUTH_SUPPORT
 # define OAUTHminc(a)  (a)
 #else /* OAUTH_SUPPORT */
-# define OAUTHmine(a)  0
+# define OAUTHminc(a)  0
 #endif /* OAUTH_SUPPORT */
 
 #define FCCS           10      /* max number of fccs allowed */
 #endif /* OAUTH_SUPPORT */
 
 #define FCCS           10      /* max number of fccs allowed */
@@ -86,7 +86,6 @@
     X("nosasl", SASLminc(6), NOSASLSW) \
     X("saslmaxssf", SASLminc(10), SASLMXSSFSW) \
     X("saslmech", SASLminc(5), SASLMECHSW) \
     X("nosasl", SASLminc(6), NOSASLSW) \
     X("saslmaxssf", SASLminc(10), SASLMXSSFSW) \
     X("saslmech", SASLminc(5), SASLMECHSW) \
-    X("authservice", SASLminc(0), AUTHSERVICESW) \
     X("user", SASLminc(-4), USERSW) \
     X("port server submission port name/number", 4, PORTSW) \
     X("tls", TLSminc(-3), TLSSW) \
     X("user", SASLminc(-4), USERSW) \
     X("port server submission port name/number", 4, PORTSW) \
     X("tls", TLSminc(-3), TLSSW) \
@@ -115,6 +114,25 @@ DEFINE_SWITCH_ARRAY(POST, switches);
 #undef X
 
 
 #undef X
 
 
+/*
+ * Mapping between command-line switches and profile entries, communicated
+ * from 'send'.  We use a service name of 'post' internally.
+ */
+
+static struct oauth_profile {
+    const char *profname;
+    int switchnum;
+} oauthswitches[] = {
+    { "oauth-post-credential-file", OAUTHCREDFILESW },
+    { "oauth-post-client_id", OAUTHCLIDSW },
+    { "oauth-post-client_secret", OAUTHCLSECSW },
+    { "oauth-post-auth_endpoint", OAUTHAUTHENDSW },
+    { "oauth-post-redirect_url", OAUTHREDIRSW },
+    { "oauth-post-token_endpoint", OAUTHTOKENDSW },
+    { "oauth-post-scope", OAUTHSCOPESW },
+    { NULL, 0 }
+};
+
 struct headers {
     char *value;
     unsigned int flags;
 struct headers {
     char *value;
     unsigned int flags;
@@ -271,14 +289,14 @@ static void anno (void);
 static int annoaux (struct mailname *);
 static void insert_fcc (struct headers *, char *);
 static void make_bcc_file (int);
 static int annoaux (struct mailname *);
 static void insert_fcc (struct headers *, char *);
 static void make_bcc_file (int);
-static void verify_all_addresses (int, char *, const char *);
+static void verify_all_addresses (int, char *, int);
 static void chkadr (void);
 static void sigon (void);
 static void sigoff (void);
 static void p_refile (char *);
 static void fcc (char *, char *);
 static void die (char *, char *, ...);
 static void chkadr (void);
 static void sigon (void);
 static void sigoff (void);
 static void p_refile (char *);
 static void fcc (char *, char *);
 static void die (char *, char *, ...);
-static void post (char *, int, int, char *, const char *);
+static void post (char *, int, int, char *, int);
 static void do_text (char *file, int fd);
 static void do_an_address (struct mailname *, int);
 static void do_addresses (int, int);
 static void do_text (char *file, int fd);
 static void do_an_address (struct mailname *, int);
 static void do_addresses (int, int);
@@ -288,12 +306,11 @@ static int find_prefix (void);
 int
 main (int argc, char **argv)
 {
 int
 main (int argc, char **argv)
 {
-    int state, compnum, dashstuff = 0;
+    int state, compnum, dashstuff = 0, swnum, oauth_flag = 0;
     char *cp, *msg = NULL, **argp, **arguments, *envelope;
     char buf[BUFSIZ], name[NAMESZ];
     FILE *in, *out;
     m_getfld_state_t gstate = 0;
     char *cp, *msg = NULL, **argp, **arguments, *envelope;
     char buf[BUFSIZ], name[NAMESZ];
     FILE *in, *out;
     m_getfld_state_t gstate = 0;
-    char *xoauth_client_res = NULL;
 
     if (nmh_init(argv[0], 0 /* use context_foil() */)) { return 1; }
 
 
     if (nmh_init(argv[0], 0 /* use context_foil() */)) { return 1; }
 
@@ -303,7 +320,7 @@ main (int argc, char **argv)
 
     while ((cp = *argp++)) {
        if (*cp == '-') {
 
     while ((cp = *argp++)) {
        if (*cp == '-') {
-           switch (smatch (++cp, switches)) {
+           switch ((swnum = smatch (++cp, switches))) {
                case AMBIGSW: 
                    ambigsw (cp, switches);
                    done (1);
                case AMBIGSW: 
                    ambigsw (cp, switches);
                    done (1);
@@ -455,14 +472,34 @@ main (int argc, char **argv)
                        adios (NULL, "missing argument to %s", argp[-2]);
                    continue;
 
                        adios (NULL, "missing argument to %s", argp[-2]);
                    continue;
 
-               case AUTHSERVICESW:
-#ifdef OAUTH_SUPPORT
-                   if (!(xoauth_client_res = *argp++) || *xoauth_client_res == '-')
+               case OAUTHCREDFILESW:
+               case OAUTHCLIDSW:
+               case OAUTHCLSECSW:
+               case OAUTHAUTHENDSW:
+               case OAUTHREDIRSW:
+               case OAUTHTOKENDSW:
+               case OAUTHSCOPESW:
+               {
+                   int i;
+
+                   if (!(cp = *argp++) || *cp == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
                        adios (NULL, "missing argument to %s", argp[-2]);
-#else
-                   adios (NULL, "not built with OAuth support");
-#endif
+
+                   for (i = 0; oauthswitches[i].profname != NULL; i++) {
+                       if (oauthswitches[i].switchnum == swnum) {
+                           add_profile_entry(oauthswitches[i].profname, cp);
+                           break;
+                       }
+                   }
+
+                   if (oauthswitches[i].profname == NULL)
+                       adios (NULL, "internal error: cannot map switch %s "
+                              "to profile entry", argp[-2]);
+
+                   oauth_flag++;
+
                    continue;
                    continue;
+               }
 
                case USERSW:
                    if (!(user = *argp++) || *user == '-')
 
                case USERSW:
                    if (!(user = *argp++) || *user == '-')
@@ -651,7 +688,7 @@ main (int argc, char **argv)
     /* If we are doing a "whom" check */
     if (whomsw) {
        /* This won't work with MTS_SENDMAIL_PIPE. */
     /* If we are doing a "whom" check */
     if (whomsw) {
        /* This won't work with MTS_SENDMAIL_PIPE. */
-        verify_all_addresses (1, envelope, xoauth_client_res);
+        verify_all_addresses (1, envelope, oauth_flag);
        done (0);
     }
 
        done (0);
     }
 
@@ -663,14 +700,14 @@ main (int argc, char **argv)
                   verify_all_addresses with MTS_SENDMAIL_PIPE, but
                   that might require running sendmail as root.  Note
                   that spost didn't verify addresses. */
                   verify_all_addresses with MTS_SENDMAIL_PIPE, but
                   that might require running sendmail as root.  Note
                   that spost didn't verify addresses. */
-               verify_all_addresses (verbose, envelope, xoauth_client_res);
+               verify_all_addresses (verbose, envelope, oauth_flag);
            }
            }
-           post (tmpfil, 0, verbose, envelope, xoauth_client_res);
+           post (tmpfil, 0, verbose, envelope, oauth_flag);
        }
        }
-       post (bccfil, 1, verbose, envelope, xoauth_client_res);
+       post (bccfil, 1, verbose, envelope, oauth_flag);
        (void) m_unlink (bccfil);
     } else {
        (void) m_unlink (bccfil);
     } else {
-       post (tmpfil, 0, isatty (1), envelope, xoauth_client_res);
+       post (tmpfil, 0, isatty (1), envelope, oauth_flag);
     }
 
     p_refile (tmpfil);
     }
 
     p_refile (tmpfil);
@@ -1517,8 +1554,7 @@ do_addresses (int bccque, int talk)
  */
 
 static void
  */
 
 static void
-post (char *file, int bccque, int talk, char *envelope,
-      const char *xoauth_client_res)
+post (char *file, int bccque, int talk, char *envelope, int oauth_flag)
 {
     int fd;
     int        retval, i;
 {
     int fd;
     int        retval, i;
@@ -1568,7 +1604,8 @@ post (char *file, int bccque, int talk, char *envelope,
     } else {
         if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
                                         verbose, snoop, sasl, saslssf,
     } else {
         if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
                                         verbose, snoop, sasl, saslssf,
-                                       saslmech, user, xoauth_client_res, tls))
+                                       saslmech, user,
+                                       oauth_flag ? "post" : NULL, tls))
             || rp_isbad (retval = sm_winit (envelope)))
            die (NULL, "problem initializing server; %s", rp_string (retval));
 
             || rp_isbad (retval = sm_winit (envelope)))
            die (NULL, "problem initializing server; %s", rp_string (retval));
 
@@ -1598,7 +1635,7 @@ post (char *file, int bccque, int talk, char *envelope,
 /* Address Verification */
 
 static void
 /* Address Verification */
 
 static void
-verify_all_addresses (int talk, char *envelope, const char *xoauth_client_res)
+verify_all_addresses (int talk, char *envelope, int oauth_flag)
 {
     int retval;
     struct mailname *lp;
 {
     int retval;
     struct mailname *lp;
@@ -1608,7 +1645,8 @@ verify_all_addresses (int talk, char *envelope, const char *xoauth_client_res)
     if (!whomsw || checksw)
        if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
                                        verbose, snoop, sasl, saslssf,
     if (!whomsw || checksw)
        if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
                                        verbose, snoop, sasl, saslssf,
-                                       saslmech, user, xoauth_client_res, tls))
+                                       saslmech, user,
+                                       oauth_flag ? "post" : NULL, tls))
                || rp_isbad (retval = sm_winit (envelope)))
            die (NULL, "problem initializing server; %s", rp_string (retval));
 
                || rp_isbad (retval = sm_winit (envelope)))
            die (NULL, "problem initializing server; %s", rp_string (retval));
 
index 89894af58a1978cad7343fa29717fd6c9bdfc3df..62229340e5b4969f196126bc7f35761b240bbc37 100644 (file)
@@ -26,7 +26,7 @@
 #ifdef OAUTH_SUPPORT
 #include <h/oauth.h>
 
 #ifdef OAUTH_SUPPORT
 #include <h/oauth.h>
 
-static int setup_oauth_params(char *[], int *, int, const char **);
+static int setup_oauth_params(char *[], int *, const char **);
 #endif /* OAUTH_SUPPORT */
 
 int debugsw = 0;               /* global */
 #endif /* OAUTH_SUPPORT */
 
 int debugsw = 0;               /* global */
@@ -749,17 +749,7 @@ handle_sendfrom(char **vec, int *vecp, char *draft) {
         for (vp = vec; *vp; ++vp) {
             if (strcmp(*vp, "xoauth2") == 0) {
 #ifdef OAUTH_SUPPORT
         for (vp = vec; *vp; ++vp) {
             if (strcmp(*vp, "xoauth2") == 0) {
 #ifdef OAUTH_SUPPORT
-                int snoop = 0;
-
-                /* -snoop will be in vec if it was enabled. */
-                for (vp = vec; vp && *vp; ++vp) {
-                    if (strcmp(*vp, "-snoop") == 0) {
-                        snoop = 1;
-                        break;
-                    }
-                }
-
-                if (setup_oauth_params(vec, vecp, snoop, &message) != OK) {
+                if (setup_oauth_params(vec, vecp, &message) != OK) {
                     adios(NULL, message);
                 }
                 break;
                     adios(NULL, message);
                 }
                 break;
@@ -775,12 +765,13 @@ handle_sendfrom(char **vec, int *vecp, char *draft) {
 
 #ifdef OAUTH_SUPPORT
 /*
 
 #ifdef OAUTH_SUPPORT
 /*
- * For XOAUTH2, append access token, from mh_oauth_do_xoauth(), for the user to vec.
+ * For XOAUTH2, append profile entries so post can do the heavy lifting
  */
  */
-static
-int
-setup_oauth_params(char *vec[], int *vecp, int snoop, const char **message) {
+static int
+setup_oauth_params(char *vec[], int *vecp, const char **message) {
     const char *saslmech = NULL, *user = NULL, *auth_svc = NULL;
     const char *saslmech = NULL, *user = NULL, *auth_svc = NULL;
+    mh_oauth_service_info svc;
+    char errbuf[256];
     int i;
 
     /* Make sure we have all the information we need. */
     int i;
 
     /* Make sure we have all the information we need. */
@@ -807,6 +798,7 @@ setup_oauth_params(char *vec[], int *vecp, int snoop, const char **message) {
             return NOTOK;
         }
 
             return NOTOK;
         }
 
+       
         vec[(*vecp)++] = getcpy("-authservice");
         if (saslmech  &&  ! strcasecmp(saslmech, "xoauth2")) {
             vec[(*vecp)++] = mh_oauth_do_xoauth(user, auth_svc, snoop ? stderr : NULL);
         vec[(*vecp)++] = getcpy("-authservice");
         if (saslmech  &&  ! strcasecmp(saslmech, "xoauth2")) {
             vec[(*vecp)++] = mh_oauth_do_xoauth(user, auth_svc, snoop ? stderr : NULL);