summaryrefslogtreecommitdiff
path: root/usr/src/cmd/mailx/head.c
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2014-12-23 23:19:21 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2014-12-23 23:19:21 +0000
commitaf9034a8036f884fc06874c445d85ac9f416f4fe (patch)
tree01ceaeec83dcf7e2bab07cbf2db7f40b7fcb5622 /usr/src/cmd/mailx/head.c
parent8af96fbb6bb47d4566bcfef02a8e551164eb2208 (diff)
parent5422785d352a2bb398daceab3d1898a8aa64d006 (diff)
downloadillumos-joyent-release-20141225.tar.gz
[illumos-gate merge]20141225release-20141225
commit 5422785d352a2bb398daceab3d1898a8aa64d006 5481 CVE-2012-1750 mailx(1) tilde expansion vulnerability 5482 CVE-2014-7844, CVE-2004-2771 - more mailx(1) woes commit 196c7f05d2deba7404e90ad67f3861185c78ca2d 5480 CVE-2012-3165 mailx(1) buffer overflow vulnerability
Diffstat (limited to 'usr/src/cmd/mailx/head.c')
-rw-r--r--usr/src/cmd/mailx/head.c242
1 files changed, 160 insertions, 82 deletions
diff --git a/usr/src/cmd/mailx/head.c b/usr/src/cmd/mailx/head.c
index 3f833ab14e..b6d09f0767 100644
--- a/usr/src/cmd/mailx/head.c
+++ b/usr/src/cmd/mailx/head.c
@@ -19,6 +19,11 @@
*
* CDDL HEADER END
*/
+
+/*
+ * Copyright 2014 Joyent, Inc.
+ */
+
/*
* Copyright 1995 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -38,7 +43,7 @@
* contributors.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+#include <err.h>
#include "rcv.h"
@@ -49,115 +54,188 @@
* Routines for processing and detecting headlines.
*/
-static char *copyin(char src[], char **space);
-static char *nextword(char wp[], char wbuf[]);
+static int nextword(const char *, custr_t *, const char **);
/*
* See if the passed line buffer is a mail header.
* Return true if yes.
*/
-
-int
-ishead(char linebuf[])
+boolean_t
+is_headline(const char *linebuf)
{
- register char *cp;
- struct headline hl;
- char parbuf[BUFSIZ];
-
- cp = linebuf;
- if (strncmp("From ", cp, 5) != 0)
- return(0);
- parse(cp, &hl, parbuf);
- if (hl.l_from == NOSTR) {
- return(0);
+ headline_t *hl;
+ boolean_t ret;
+
+ if (strncmp("From ", linebuf, 5) != 0) {
+ return (B_FALSE);
+ }
+
+ if (headline_alloc(&hl) != 0 || parse_headline(linebuf, hl) != 0) {
+ err(1, "could not parse headline");
}
- return(1);
+
+ ret = custr_len(hl->hl_from) > 0 ? B_TRUE : B_FALSE;
+
+ headline_free(hl);
+ return (ret);
}
/*
- * Split a headline into its useful components.
- * Copy the line into dynamic string space, then set
- * pointers into the copied line in the passed headline
- * structure. Actually, it scans.
+ * Manage headline_t objects:
*/
-void
-parse(char line[], struct headline *hl, char pbuf[])
+void
+headline_free(headline_t *hl)
+{
+ custr_free(hl->hl_from);
+ custr_free(hl->hl_tty);
+ custr_free(hl->hl_date);
+ free(hl);
+}
+
+int
+headline_alloc(headline_t **hl)
{
- register char *cp, *dp;
- char *sp;
- char word[LINESIZE];
+ int en;
+ headline_t *t;
+
+ if ((t = calloc(1, sizeof (*t))) == NULL) {
+ return (-1);
+ }
- hl->l_from = NOSTR;
- hl->l_date = NOSTR;
- cp = line;
- sp = pbuf;
+ if (custr_alloc(&t->hl_from) != 0 || custr_alloc(&t->hl_tty) != 0 ||
+ custr_alloc(&t->hl_date) != 0) {
+ en = errno;
- /*
- * Skip the first "word" of the line, which should be "From"
- * anyway.
- */
+ headline_free(t);
- cp = nextword(cp, word);
- dp = nextword(cp, word);
- if (!equal(word, ""))
- hl->l_from = copyin(word, &sp);
- if (dp != NOSTR)
- hl->l_date = copyin(dp, &sp);
+ errno = en;
+ return (-1);
+ }
+
+ *hl = t;
+ return (0);
}
/*
- * Copy the string on the left into the string on the right
- * and bump the right (reference) string pointer by the length.
- * Thus, dynamically allocate space in the right string, copying
- * the left string into it.
+ * Clear all of the strings in a headline_t:
*/
+void
+headline_reset(headline_t *hl)
+{
+ custr_reset(hl->hl_from);
+ custr_reset(hl->hl_tty);
+ custr_reset(hl->hl_date);
+}
-static char *
-copyin(char src[], char **space)
+int
+parse_headline(const char *line, headline_t *hl)
{
- register char *cp, *top;
- register int s;
-
- s = strlen(src);
- cp = *space;
- top = cp;
- strcpy(cp, src);
- cp += s + 1;
- *space = cp;
- return(top);
+ const char *c = line;
+
+ headline_reset(hl);
+
+ /*
+ * Load the first word from the line and ensure that it is "From".
+ */
+ if (nextword(c, hl->hl_from, &c) != 0) {
+ return (-1);
+ }
+ if (strcmp(custr_cstr(hl->hl_from), "From") != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ custr_reset(hl->hl_from);
+
+ /*
+ * The next word will be the From address.
+ */
+ if (nextword(c, hl->hl_from, &c) != 0) {
+ return (-1);
+ }
+
+ /*
+ * If there is a next word, the rest of the string is the Date.
+ */
+ if (c != NULL) {
+ if (custr_append(hl->hl_date, c) != 0) {
+ return (-1);
+ }
+ }
+
+ errno = 0;
+ return (0);
}
/*
- * Collect a liberal (space, tab delimited) word into the word buffer
- * passed. Also, return a pointer to the next word following that,
- * or NOSTR if none follow.
+ * Collect a space- or tab-delimited word into the word buffer, if one is
+ * passed. The double quote character (") can be used to include whitespace
+ * within a word. Set "nextword" to the location of the first character of the
+ * _next_ word, or NULL if there were no more words. Returns 0 on success or
+ * -1 otherwise.
*/
-
-static char *
-nextword(char wp[], char wbuf[])
+static int
+nextword(const char *input, custr_t *word, const char **nextword)
{
- register char *cp, *cp2;
+ boolean_t in_quotes = B_FALSE;
+ const char *c = input != NULL ? input : "";
+
+ /*
+ * Collect the first word into the word buffer, if one is provided.
+ */
+ for (;;) {
+ if (*c == '\0') {
+ /*
+ * We have reached the end of the string.
+ */
+ *nextword = NULL;
+ return (0);
+ }
+
+ if (*c == '"') {
+ /*
+ * Either beginning or ending a quoted string.
+ */
+ in_quotes = in_quotes ? B_FALSE : B_TRUE;
+ }
+
+ if (!in_quotes && (*c == ' ' || *c == '\t')) {
+ /*
+ * We have reached a whitespace region.
+ */
+ break;
+ }
+
+ /*
+ * Copy this character into the word buffer.
+ */
+ if (word != NULL) {
+ if (custr_appendc(word, *c) != 0) {
+ return (-1);
+ }
+ }
+ c++;
+ }
+
+ /*
+ * Find the beginning of the next word, if there is one.
+ */
+ for (;;) {
+ if (*c == '\0') {
+ /*
+ * We have reached the end of the string.
+ */
+ *nextword = NULL;
+ return (0);
- if ((cp = wp) == NOSTR) {
- copy("", wbuf);
- return(NOSTR);
+ } else if (*c != ' ' && *c != '\t') {
+ /*
+ * We have located the next word.
+ */
+ *nextword = c;
+ return (0);
+ }
+ c++;
}
- cp2 = wbuf;
- while (!any(*cp, " \t") && *cp != '\0')
- if (*cp == '"') {
- *cp2++ = *cp++;
- while (*cp != '\0' && *cp != '"')
- *cp2++ = *cp++;
- if (*cp == '"')
- *cp2++ = *cp++;
- } else
- *cp2++ = *cp++;
- *cp2 = '\0';
- while (any(*cp, " \t"))
- cp++;
- if (*cp == '\0')
- return(NOSTR);
- return(cp);
}
/*