Merge branch 'rs/imap-send-next-arg-fix' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 27 Nov 2017 01:57:00 +0000 (10:57 +0900)
committerJunio C Hamano <gitster@pobox.com>
Mon, 27 Nov 2017 01:57:00 +0000 (10:57 +0900)
Error checking in "git imap-send" for empty response has been
improved.

* rs/imap-send-next-arg-fix:
imap-send: handle missing response codes gracefully
imap-send: handle NULL return of next_arg()

1  2 
imap-send.c
diff --combined imap-send.c
index e0523d3427205065037a493750da03fbefd1c8f4,efa6af4b511219821875414def17dd2b727228fc..54e6a80fd64e16420a526461e90aed559e0bd1d6
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
 - *  along with this program; if not, write to the Free Software
 - *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 + *  along with this program; if not, see <http://www.gnu.org/licenses/>.
   */
  
  #include "cache.h"
 +#include "config.h"
  #include "credential.h"
  #include "exec_cmd.h"
  #include "run-command.h"
@@@ -34,11 -34,11 +34,11 @@@ typedef void *SSL
  #include "http.h"
  #endif
  
 -#if defined(USE_CURL_FOR_IMAP_SEND) && defined(NO_OPENSSL)
 -/* only available option */
 +#if defined(USE_CURL_FOR_IMAP_SEND)
 +/* Always default to curl if it's available. */
  #define USE_CURL_DEFAULT 1
  #else
 -/* strictly opt in */
 +/* We don't have curl, so continue to use the historical implementation */
  #define USE_CURL_DEFAULT 0
  #endif
  
@@@ -683,7 -683,7 +683,7 @@@ static int parse_response_code(struct i
        struct imap *imap = ctx->imap;
        char *arg, *p;
  
-       if (*s != '[')
+       if (!s || *s != '[')
                return RESP_OK;         /* no response code */
        s++;
        if (!(p = strchr(s, ']'))) {
        }
        *p++ = 0;
        arg = next_arg(&s);
+       if (!arg) {
+               fprintf(stderr, "IMAP error: empty response code\n");
+               return RESP_BAD;
+       }
        if (!strcmp("UIDVALIDITY", arg)) {
                if (!(arg = next_arg(&s)) || !(ctx->uidvalidity = atoi(arg))) {
                        fprintf(stderr, "IMAP error: malformed UIDVALIDITY status\n");
@@@ -724,7 -728,8 +728,8 @@@ static int get_cmd_result(struct imap_s
  {
        struct imap *imap = ctx->imap;
        struct imap_cmd *cmdp, **pcmdp;
-       char *cmd, *arg, *arg1;
+       char *cmd;
+       const char *arg, *arg1;
        int n, resp, resp2, tag;
  
        for (;;) {
                        return RESP_BAD;
  
                arg = next_arg(&cmd);
+               if (!arg) {
+                       fprintf(stderr, "IMAP error: empty response\n");
+                       return RESP_BAD;
+               }
                if (*arg == '*') {
                        arg = next_arg(&cmd);
                        if (!arg) {
                               offsetof(struct imap_cmd, next));
                        if (cmdp->cb.data) {
                                n = socket_write(&imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen);
 -                              free(cmdp->cb.data);
 -                              cmdp->cb.data = NULL;
 +                              FREE_AND_NULL(cmdp->cb.data);
                                if (n != (int)cmdp->cb.dlen)
                                        return RESP_BAD;
                        } else if (cmdp->cb.cont) {
                        if (cmdp->cb.cont || cmdp->cb.data)
                                imap->literal_pending = 0;
                        arg = next_arg(&cmd);
+                       if (!arg)
+                               arg = "";
                        if (!strcmp("OK", arg))
                                resp = DRV_OK;
                        else {
@@@ -860,7 -872,7 +871,7 @@@ static char hexchar(unsigned int b
        return b < 10 ? '0' + b : 'a' + (b - 10);
  }
  
 -#define ENCODED_SIZE(n) (4*((n+2)/3))
 +#define ENCODED_SIZE(n) (4 * DIV_ROUND_UP((n), 3))
  static char *cram(const char *challenge_64, const char *user, const char *pass)
  {
        int i, resp_len, encoded_len, decoded_len;
@@@ -925,25 -937,6 +936,25 @@@ static int auth_cram_md5(struct imap_st
        return 0;
  }
  
 +static void server_fill_credential(struct imap_server_conf *srvc, struct credential *cred)
 +{
 +      if (srvc->user && srvc->pass)
 +              return;
 +
 +      cred->protocol = xstrdup(srvc->use_ssl ? "imaps" : "imap");
 +      cred->host = xstrdup(srvc->host);
 +
 +      cred->username = xstrdup_or_null(srvc->user);
 +      cred->password = xstrdup_or_null(srvc->pass);
 +
 +      credential_fill(cred);
 +
 +      if (!srvc->user)
 +              srvc->user = xstrdup(cred->username);
 +      if (!srvc->pass)
 +              srvc->pass = xstrdup(cred->password);
 +}
 +
  static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *folder)
  {
        struct credential cred = CREDENTIAL_INIT;
                int gai;
                char portstr[6];
  
 -              snprintf(portstr, sizeof(portstr), "%d", srvc->port);
 +              xsnprintf(portstr, sizeof(portstr), "%d", srvc->port);
  
                memset(&hints, 0, sizeof(hints));
                hints.ai_socktype = SOCK_STREAM;
                }
  #endif
                imap_info("Logging in...\n");
 -              if (!srvc->user || !srvc->pass) {
 -                      cred.protocol = xstrdup(srvc->use_ssl ? "imaps" : "imap");
 -                      cred.host = xstrdup(srvc->host);
 -
 -                      cred.username = xstrdup_or_null(srvc->user);
 -                      cred.password = xstrdup_or_null(srvc->pass);
 -
 -                      credential_fill(&cred);
 -
 -                      if (!srvc->user)
 -                              srvc->user = xstrdup(cred.username);
 -                      if (!srvc->pass)
 -                              srvc->pass = xstrdup(cred.password);
 -              }
 +              server_fill_credential(srvc, &cred);
  
                if (srvc->auth_method) {
                        struct imap_cmd_cb cb;
@@@ -1397,7 -1403,7 +1408,7 @@@ static int append_msgs_to_imap(struct i
  }
  
  #ifdef USE_CURL_FOR_IMAP_SEND
 -static CURL *setup_curl(struct imap_server_conf *srvc)
 +static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
  {
        CURL *curl;
        struct strbuf path = STRBUF_INIT;
        if (!curl)
                die("curl_easy_init failed");
  
 +      server_fill_credential(&server, cred);
        curl_easy_setopt(curl, CURLOPT_USERNAME, server.user);
        curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);
  
@@@ -1460,9 -1465,8 +1471,9 @@@ static int curl_append_msgs_to_imap(str
        struct buffer msgbuf = { STRBUF_INIT, 0 };
        CURL *curl;
        CURLcode res = CURLE_OK;
 +      struct credential cred = CREDENTIAL_INIT;
  
 -      curl = setup_curl(server);
 +      curl = setup_curl(server, &cred);
        curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
  
        fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
        curl_easy_cleanup(curl);
        curl_global_cleanup();
  
 -      return 0;
 +      if (cred.username) {
 +              if (res == CURLE_OK)
 +                      credential_approve(&cred);
 +#if LIBCURL_VERSION_NUM >= 0x070d01
 +              else if (res == CURLE_LOGIN_DENIED)
 +#else
 +              else
 +#endif
 +                      credential_reject(&cred);
 +      }
 +
 +      credential_clear(&cred);
 +
 +      return res != CURLE_OK;
  }
  #endif