imap-send: increase command size limit

nfvasprintf() has a 8KB limit, but it's not relevant, as its result is combined with other strings and added to a 1KB buffer by its caller. That 1KB limit is not mentioned in RFC 9051, which specifies IMAP. While 1KB is plenty for user names, passwords and mailbox names, there's no point in limiting our commands like that. Call xstrvfmt() instead of open-coding it and use strbuf to format the command to send, as we need its length. Fail hard if it exceeds INT_MAX, because socket_write() can't take more than that. Suggested-by: Jeff King <peff@peff.net> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed Apr 14, 2024 at 18:47 UTC 21b5821acd6a5627d2efcc22021f8f040373a69c
1 file changed +12 -23
imap-send.c
+12 -23
@@ -68,20 +68,6 @@ static void imap_warn(const char *, ...);
68
69 static char *next_arg(char **);
70
71 -static int nfvasprintf(char **strp, const char *fmt, va_list ap)
72 -{
73 - int len;
74 - char tmp[8192];
75 -
76 - len = vsnprintf(tmp, sizeof(tmp), fmt, ap);
77 - if (len < 0)
78 - die("Fatal: Out of memory");
79 - if (len >= sizeof(tmp))
80 - die("imap command overflow!");
81 - *strp = xmemdupz(tmp, len);
82 - return len;
83 -}
84 -
71 struct imap_server_conf {
72 const char *name;
73 const char *tunnel;
@@ -503,11 +489,11 @@ static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
489 {
490 struct imap *imap = ctx->imap;
491 struct imap_cmd *cmd;
506 - int n, bufl;
507 - char buf[1024];
492 + int n;
493 + struct strbuf buf = STRBUF_INIT;
494
495 cmd = xmalloc(sizeof(struct imap_cmd));
510 - nfvasprintf(&cmd->cmd, fmt, ap);
496 + cmd->cmd = xstrvfmt(fmt, ap);
497 cmd->tag = ++imap->nexttag;
498
499 if (cb)
@@ -519,27 +505,30 @@ static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
505 get_cmd_result(ctx, NULL);
506
507 if (!cmd->cb.data)
522 - bufl = xsnprintf(buf, sizeof(buf), "%d %s\r\n", cmd->tag, cmd->cmd);
508 + strbuf_addf(&buf, "%d %s\r\n", cmd->tag, cmd->cmd);
509 else
524 - bufl = xsnprintf(buf, sizeof(buf), "%d %s{%d%s}\r\n",
525 - cmd->tag, cmd->cmd, cmd->cb.dlen,
526 - CAP(LITERALPLUS) ? "+" : "");
510 + strbuf_addf(&buf, "%d %s{%d%s}\r\n", cmd->tag, cmd->cmd,
511 + cmd->cb.dlen, CAP(LITERALPLUS) ? "+" : "");
512 + if (buf.len > INT_MAX)
513 + die("imap command overflow!");
514
515 if (0 < verbosity) {
516 if (imap->num_in_progress)
517 printf("(%d in progress) ", imap->num_in_progress);
518 if (!starts_with(cmd->cmd, "LOGIN"))
532 - printf(">>> %s", buf);
519 + printf(">>> %s", buf.buf);
520 else
521 printf(">>> %d LOGIN <user> <pass>\n", cmd->tag);
522 }
536 - if (socket_write(&imap->buf.sock, buf, bufl) != bufl) {
523 + if (socket_write(&imap->buf.sock, buf.buf, buf.len) != buf.len) {
524 free(cmd->cmd);
525 free(cmd);
526 if (cb)
527 free(cb->data);
528 + strbuf_release(&buf);
529 return NULL;
530 }
531 + strbuf_release(&buf);
532 if (cmd->cb.data) {
533 if (CAP(LITERALPLUS)) {
534 n = socket_write(&imap->buf.sock, cmd->cb.data, cmd->cb.dlen);