summaryrefslogtreecommitdiff
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
parent8af96fbb6bb47d4566bcfef02a8e551164eb2208 (diff)
parent5422785d352a2bb398daceab3d1898a8aa64d006 (diff)
downloadillumos-joyent-af9034a8036f884fc06874c445d85ac9f416f4fe.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
-rw-r--r--usr/src/cmd/Makefile1
-rw-r--r--usr/src/cmd/fmt/Makefile1
-rw-r--r--usr/src/cmd/fmt/fmt.c6
-rw-r--r--usr/src/cmd/mailx/Makefile4
-rw-r--r--usr/src/cmd/mailx/cmd1.c34
-rw-r--r--usr/src/cmd/mailx/fio.c10
-rw-r--r--usr/src/cmd/mailx/hdr/def.h22
-rw-r--r--usr/src/cmd/mailx/head.c242
-rw-r--r--usr/src/cmd/mailx/main.c3
-rw-r--r--usr/src/cmd/mailx/misc/mailx.rc4
-rw-r--r--usr/src/cmd/mailx/names.c19
-rw-r--r--usr/src/cmd/mailx/receipt.c26
-rw-r--r--usr/src/lib/libcmdutils/Makefile.com3
-rw-r--r--usr/src/lib/libcmdutils/common/custr.c135
-rw-r--r--usr/src/lib/libcmdutils/common/mapfile-vers7
-rw-r--r--usr/src/lib/libcmdutils/libcmdutils.h43
-rw-r--r--usr/src/man/man1/mailx.150
17 files changed, 459 insertions, 151 deletions
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index d16130bd8f..f78feac556 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -824,6 +824,7 @@ fs.d: fstyp
ksh: shcomp isaexec
mdb: terminfo
print: lp
+fmt: mailx
$(FIRST_SUBDIRS) $(BWOSDIRS) $(SUBDIRS) $(AUDITSUBDIRS): FRC
@if [ -f $@/Makefile ]; then \
diff --git a/usr/src/cmd/fmt/Makefile b/usr/src/cmd/fmt/Makefile
index 21938536d6..cecd4e3c2a 100644
--- a/usr/src/cmd/fmt/Makefile
+++ b/usr/src/cmd/fmt/Makefile
@@ -33,6 +33,7 @@ SRCS= $(OBJS:%.o=%.c)
include ../Makefile.cmd
+LDLIBS += -lcmdutils
CERRWARN += -_gcc=-Wno-switch
CERRWARN += -_gcc=-Wno-parentheses
diff --git a/usr/src/cmd/fmt/fmt.c b/usr/src/cmd/fmt/fmt.c
index 52d4676172..b5fbee6e13 100644
--- a/usr/src/cmd/fmt/fmt.c
+++ b/usr/src/cmd/fmt/fmt.c
@@ -86,7 +86,7 @@ int h_lines; /* index into lines of hdrbuf */
void (*(split))(wchar_t []);
extern int scrwidth(wchar_t);
-extern int ishead(char []);
+extern boolean_t is_headline(const char *);
static void fill_hdrbuf(wchar_t []);
@@ -240,13 +240,13 @@ fmt(FILE *fi)
}
/*
* Need to convert string from wchar_t to char,
- * since this is what ishead() expects. Since we
+ * since this is what is_headline() expects. Since we
* only want to make sure cp points to a "From" line
* of the email, we don't have to alloc
* BUFSIZ * MB_LEN_MAX to cbuf.
*/
wcstombs(cbuf, cp, (BUFSIZ - 1));
- if (ishead(cbuf)) {
+ if (is_headline(cbuf) == B_TRUE) {
hdr_state = in_hdr;
fill_hdrbuf(canonb);
} else {
diff --git a/usr/src/cmd/mailx/Makefile b/usr/src/cmd/mailx/Makefile
index 93b527b72a..4fb19334f2 100644
--- a/usr/src/cmd/mailx/Makefile
+++ b/usr/src/cmd/mailx/Makefile
@@ -22,6 +22,8 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2014 Joyent, Inc.
+#
# cmd/mailx/Makefile
PROG= mailx
@@ -67,7 +69,7 @@ CERRWARN += -_gcc=-Wno-uninitialized
CERRWARN += -_gcc=-Wno-unused-variable
CERRWARN += -_gcc=-Wno-clobbered
LINTFLAGS= -hb
-LDLIBS += -lmail
+LDLIBS += -lmail -lcmdutils
LDFLAGS += $(MAPFILE.NGB:%=-M%)
CLOBBERFILES += $(MAILXHELP)
diff --git a/usr/src/cmd/mailx/cmd1.c b/usr/src/cmd/mailx/cmd1.c
index 5cdb7ae465..38c9b7ab9b 100644
--- a/usr/src/cmd/mailx/cmd1.c
+++ b/usr/src/cmd/mailx/cmd1.c
@@ -19,6 +19,11 @@
*
* CDDL HEADER END
*/
+
+/*
+ * Copyright 2014 Joyent, Inc.
+ */
+
/*
* Copyright 2001 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -37,8 +42,7 @@
* contributors.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
+#include <err.h>
#include "rcv.h"
#include <locale.h>
@@ -213,10 +217,14 @@ printhead(int mesg)
char *fromline;
char pbuf[LINESIZE];
char name[LINESIZE];
- struct headline hl;
+ headline_t *hl;
register char *cp;
int showto;
+ if (headline_alloc(&hl) != 0) {
+ err(1, "could not allocate memory");
+ }
+
mp = &message[mesg-1];
ibuf = setinput(mp);
readline(ibuf, headline);
@@ -248,9 +256,14 @@ printhead(int mesg)
dispc = 'H';
if (mp->m_flag & MBOX)
dispc = 'M';
- parse(headline, &hl, pbuf);
- if (hl.l_date == NOSTR)
- hl.l_date = "<Unknown date>";
+ if (parse_headline(headline, hl) == -1) {
+ headline_reset(hl);
+ }
+ if (custr_len(hl->hl_date) == 0) {
+ if (custr_append(hl->hl_date, "<Unknown date>") != 0) {
+ err(1, "could not print header");
+ }
+ }
/*
* Netnews interface?
@@ -299,11 +312,14 @@ printhead(int mesg)
}
if (mp->m_text) {
printf("%16.16s %4ld/%-5ld %-.25s\n",
- hl.l_date, mp->m_lines, mp->m_size, subjline);
- } else {
- printf("%16.16s binary/%-5ld %-.25s\n", hl.l_date, mp->m_size,
+ custr_cstr(hl->hl_date), mp->m_lines, mp->m_size,
subjline);
+ } else {
+ printf("%16.16s binary/%-5ld %-.25s\n", custr_cstr(hl->hl_date),
+ mp->m_size, subjline);
}
+
+ headline_free(hl);
}
/*
diff --git a/usr/src/cmd/mailx/fio.c b/usr/src/cmd/mailx/fio.c
index 818860d7ae..53907ca760 100644
--- a/usr/src/cmd/mailx/fio.c
+++ b/usr/src/cmd/mailx/fio.c
@@ -21,6 +21,10 @@
*/
/*
+ * Copyright 2014 Joyent, Inc.
+ */
+
+/*
* Copyright 1999 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,8 +32,6 @@
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "rcv.h"
#include <locale.h>
#include <wordexp.h>
@@ -174,7 +176,7 @@ setptr(register FILE *ibuf)
}
/* Look for a From line that starts a new message */
- if (blankline && linebuf[0] == 'F' && ishead(linebuf)) {
+ if (blankline && linebuf[0] == 'F' && is_headline(linebuf)) {
if (msgCount > 0 && !newmail) {
message[msgCount-1].m_size = s;
message[msgCount-1].m_lines = l;
@@ -755,7 +757,7 @@ expand(char *name)
if (debug) fprintf(stderr, "%s\n", name);
return (name);
}
- if (wordexp(name, &wrdexp_buf, 0) != 0) {
+ if (wordexp(name, &wrdexp_buf, WRDE_NOCMD) != 0) {
fprintf(stderr, gettext("Syntax error in \"%s\"\n"), name);
fflush(stderr);
return (NOSTR);
diff --git a/usr/src/cmd/mailx/hdr/def.h b/usr/src/cmd/mailx/hdr/def.h
index d0e48820ea..7453b24f97 100644
--- a/usr/src/cmd/mailx/hdr/def.h
+++ b/usr/src/cmd/mailx/hdr/def.h
@@ -20,6 +20,10 @@
*/
/*
+ * Copyright 2014 Joyent, Inc.
+ */
+
+/*
* Copyright (c) 1985, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -60,6 +64,7 @@ extern "C" {
#include <stdlib.h>
#include <ulimit.h>
#include <wait.h>
+#include <libcmdutils.h>
#endif
#ifdef VMUNIX
#include <sys/wait.h>
@@ -204,11 +209,11 @@ struct cmd {
* line
*/
-struct headline {
- char *l_from; /* The name of the sender */
- char *l_tty; /* His tty string (if any) */
- char *l_date; /* The entire date string */
-};
+typedef struct headline {
+ custr_t *hl_from; /* The name of the sender */
+ custr_t *hl_tty; /* His tty string (if any) */
+ custr_t *hl_date; /* The entire date string */
+} headline_t;
#define GTO 1 /* Grab To: line */
#define GSUBJECT 2 /* Likewise, Subject: line */
@@ -486,6 +491,9 @@ extern int hash(char name[]);
extern char *hcontents(char hfield[]);
extern int headerp(register char *line);
extern int headers(int *msgvec);
+extern int headline_alloc(headline_t **);
+extern void headline_free(headline_t *);
+extern void headline_reset(headline_t *);
extern int help(void);
extern char *helppath(char *file);
extern char *hfield(char field[], struct message *mp,
@@ -497,7 +505,7 @@ extern int igfield(char *list[]);
extern int inc(void);
extern void inithost(void);
extern int isdir(char name[]);
-extern int ishead(char linebuf[]);
+extern boolean_t is_headline(const char *);
extern int ishfield(char linebuf[], char field[]);
extern int ishost(char *sys, char *rest);
extern int isign(char *field, int saving);
@@ -533,7 +541,7 @@ extern int null(char *e);
extern int outof(struct name *names, FILE *fo);
extern struct name *outpre(struct name *to);
extern void panic(char *str);
-extern void parse(char line[], struct headline *hl, char pbuf[]);
+extern int parse_headline(const char *, headline_t *);
extern int pcmdlist(void);
extern int pdot(void);
extern int preserve(int *msgvec);
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);
}
/*
diff --git a/usr/src/cmd/mailx/main.c b/usr/src/cmd/mailx/main.c
index 35448ecf7c..0271552bea 100644
--- a/usr/src/cmd/mailx/main.c
+++ b/usr/src/cmd/mailx/main.c
@@ -37,8 +37,6 @@
* contributors.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "rcv.h"
#ifndef preSVr4
#include <locale.h>
@@ -104,7 +102,6 @@ main(int argc, char **argv)
progname = argv[0];
if (progname[strlen(progname) - 1] != 'x') {
assign("bsdcompat", "");
- assign("escapeok", ""); /* XXX */
}
myegid = getegid();
myrgid = getgid();
diff --git a/usr/src/cmd/mailx/misc/mailx.rc b/usr/src/cmd/mailx/misc/mailx.rc
index d10391f433..a6dfa46fb2 100644
--- a/usr/src/cmd/mailx/misc/mailx.rc
+++ b/usr/src/cmd/mailx/misc/mailx.rc
@@ -21,8 +21,6 @@
# Copyright 2000 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# The following 3 settings produce the familiar Solaris behavior.
set appenddeadletter
unset pipeignore
@@ -44,8 +42,6 @@ else
set LISTER="ls -LF"
# default is to allow editing of message windows
set editmessagewindow
- # have to allow ~ escapes even though not using tty
- set escapeok
endif
# most mail headers are uninteresting to most people. here we ignore all
diff --git a/usr/src/cmd/mailx/names.c b/usr/src/cmd/mailx/names.c
index 7616630f79..886eb2dbc5 100644
--- a/usr/src/cmd/mailx/names.c
+++ b/usr/src/cmd/mailx/names.c
@@ -191,7 +191,7 @@ outpre(struct name *to)
/*
* For each recipient in the passed name list with a /
* in the name, append the message to the end of the named file
- * and remove him from the recipient list.
+ * and remove them from the recipient list.
*
* Recipients whose name begins with | are piped through the given
* program and removed.
@@ -212,6 +212,9 @@ outof(struct name *names, FILE *fo)
char line[BUFSIZ];
#endif
+ if (value("expandaddr") == NOSTR)
+ return (nout);
+
for (np = names; np != NIL; np = np->n_flink) {
if (!isfileaddr(np->n_name) && np->n_name[0] != '|')
continue;
@@ -599,14 +602,15 @@ unpack(struct name *np)
panic("No names to unpack");
/*
- * Compute the number of extra arguments we will need.
- * We need at least 2 extra -- one for "mail" and one for
- * the terminating 0 pointer.
- * Additional spots may be needed to pass along -r and -f to
- * the host mailer.
+ * Compute the number of extra arguments we will need. We need at least
+ * 3 extra -- one for "mail", one for a terminating -- to stop sendmail
+ * option processing, and one for the terminating 0 pointer.
+ *
+ * Additional spots may be needed to pass along -r and -f to the host
+ * mailer.
*/
- extra = 2;
+ extra = 3;
if (rflag != NOSTR)
extra += 2;
@@ -636,6 +640,7 @@ unpack(struct name *np)
snprintf(hbuf, sizeof (hbuf), "%d", hflag);
*ap++ = savestr(hbuf);
}
+ *ap++ = "--";
while (n != NIL) {
if (n->n_type & GDEL) {
n = n->n_flink;
diff --git a/usr/src/cmd/mailx/receipt.c b/usr/src/cmd/mailx/receipt.c
index 2a128d6a91..0b6b9296fc 100644
--- a/usr/src/cmd/mailx/receipt.c
+++ b/usr/src/cmd/mailx/receipt.c
@@ -19,6 +19,11 @@
*
* CDDL HEADER END
*/
+
+/*
+ * Copyright 2014 Joyent, Inc.
+ */
+
/*
* Copyright 1998 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"
@@ -47,12 +52,12 @@ static int icsubstr(char *s1, char *s2);
void
receipt(struct message *mp)
{
- struct headline hl;
char head[LINESIZE];
char buf[BUFSIZ];
FILE *pp, *fp;
char *mail, *s;
+
if ((mail = value("sendmail")) == 0)
#ifdef SENDMAIL
mail = SENDMAIL;
@@ -63,16 +68,27 @@ receipt(struct message *mp)
|| icsubstr(hfield(">to", mp, addto), "/receipt")) {
snprintf(buf, sizeof (buf), "%s %s", mail, skin(nameof(mp)));
if (pp = npopen(buf, "w")) {
+ headline_t *hl;
+
+ if (headline_alloc(&hl) != 0) {
+ err(1, "could not allocate memory");
+ }
+
fp = setinput(mp);
readline(fp, head);
- parse(head, &hl, buf);
- if (hl.l_date != NOSTR)
- fprintf(pp, "Original-Date: %s\n", hl.l_date);
+ if (parse_headline(head, hl) != 0) {
+ headline_reset(hl);
+ }
+ if (custr_len(hl->hl_date) > 0) {
+ fprintf(pp, "Original-Date: %s\n",
+ custr_cstr(hl->hl_date));
+ }
if (s = hfield("message-id", mp, addone))
fprintf(pp, "Original-Message-ID: %s\n", s);
s = hfield("subject", mp, addone);
fprintf(pp, "Subject: RR: %s\n", s ? s : "(none)");
npclose(pp);
+ headline_free(hl);
}
}
}
diff --git a/usr/src/lib/libcmdutils/Makefile.com b/usr/src/lib/libcmdutils/Makefile.com
index 2f98fe5f25..ffe3c9cba5 100644
--- a/usr/src/lib/libcmdutils/Makefile.com
+++ b/usr/src/lib/libcmdutils/Makefile.com
@@ -25,7 +25,8 @@
LIBRARY= libcmdutils.a
VERS= .1
-CMD_OBJS= avltree.o sysattrs.o writefile.o process_xattrs.o uid.o gid.o
+CMD_OBJS= avltree.o sysattrs.o writefile.o process_xattrs.o uid.o gid.o \
+ custr.o
COM_OBJS= list.o
OBJECTS= $(CMD_OBJS) $(COM_OBJS)
diff --git a/usr/src/lib/libcmdutils/common/custr.c b/usr/src/lib/libcmdutils/common/custr.c
new file mode 100644
index 0000000000..1ec72de9dd
--- /dev/null
+++ b/usr/src/lib/libcmdutils/common/custr.c
@@ -0,0 +1,135 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * String utility functions with dynamic memory management.
+ */
+
+/*
+ * Copyright 2014, Joyent, Inc.
+ */
+
+#include <stdlib.h>
+#include <err.h>
+#include <string.h>
+
+#include "libcmdutils.h"
+
+struct custr {
+ size_t cus_strlen;
+ size_t cus_datalen;
+ char *cus_data;
+};
+
+#define STRING_CHUNK_SIZE 64
+
+void
+custr_reset(custr_t *cus)
+{
+ if (cus->cus_data == NULL)
+ return;
+
+ cus->cus_strlen = 0;
+ cus->cus_data[0] = '\0';
+}
+
+size_t
+custr_len(custr_t *cus)
+{
+ return (cus->cus_strlen);
+}
+
+const char *
+custr_cstr(custr_t *cus)
+{
+ return (cus->cus_data);
+}
+
+int
+custr_appendc(custr_t *cus, char newc)
+{
+ char news[2];
+
+ news[0] = newc;
+ news[1] = '\0';
+
+ return (custr_append(cus, news));
+}
+
+int
+custr_append(custr_t *cus, const char *news)
+{
+ size_t len = strlen(news);
+ size_t chunksz = STRING_CHUNK_SIZE;
+
+ while (chunksz < len) {
+ chunksz *= 2;
+ }
+
+ if (len + cus->cus_strlen + 1 >= cus->cus_datalen) {
+ char *new_data;
+ size_t new_datalen = cus->cus_datalen + chunksz;
+
+ /*
+ * Allocate replacement memory:
+ */
+ if ((new_data = malloc(new_datalen)) == NULL) {
+ return (-1);
+ }
+
+ /*
+ * Copy existing data into replacement memory and free
+ * the old memory.
+ */
+ if (cus->cus_data != NULL) {
+ (void) memcpy(new_data, cus->cus_data,
+ cus->cus_strlen + 1);
+ free(cus->cus_data);
+ }
+
+ /*
+ * Swap in the replacement buffer:
+ */
+ cus->cus_data = new_data;
+ cus->cus_datalen = new_datalen;
+ }
+ /*
+ * Append new string to existing string:
+ */
+ (void) memcpy(cus->cus_data + cus->cus_strlen, news, len + 1);
+ cus->cus_strlen += len;
+
+ return (0);
+}
+
+int
+custr_alloc(custr_t **cus)
+{
+ custr_t *t;
+
+ if ((t = calloc(1, sizeof (*t))) == NULL) {
+ *cus = NULL;
+ return (-1);
+ }
+
+ *cus = t;
+ return (0);
+}
+
+void
+custr_free(custr_t *cus)
+{
+ if (cus == NULL)
+ return;
+
+ free(cus->cus_data);
+ free(cus);
+}
diff --git a/usr/src/lib/libcmdutils/common/mapfile-vers b/usr/src/lib/libcmdutils/common/mapfile-vers
index e4c5940c31..640959e4b5 100644
--- a/usr/src/lib/libcmdutils/common/mapfile-vers
+++ b/usr/src/lib/libcmdutils/common/mapfile-vers
@@ -42,6 +42,13 @@ $mapfile_version 2
SYMBOL_VERSION SUNWprivate_1.1 {
global:
add_tnode;
+ custr_alloc;
+ custr_append;
+ custr_appendc;
+ custr_cstr;
+ custr_free;
+ custr_len;
+ custr_reset;
destroy_tree;
findnextgid;
findnextuid;
diff --git a/usr/src/lib/libcmdutils/libcmdutils.h b/usr/src/lib/libcmdutils/libcmdutils.h
index c315e0fbef..a280751c27 100644
--- a/usr/src/lib/libcmdutils/libcmdutils.h
+++ b/usr/src/lib/libcmdutils/libcmdutils.h
@@ -25,6 +25,9 @@
/*
* Copyright (c) 2013 RackTop Systems.
*/
+/*
+ * Copyright 2014 Joyent, Inc.
+ */
/*
* Declarations for the functions in libcmdutils.
@@ -140,6 +143,46 @@ extern int findnextuid(uid_t, uid_t, uid_t *);
*/
extern int findnextgid(gid_t, gid_t, gid_t *);
+
+
+ /* dynamic string utilities */
+
+typedef struct custr custr_t;
+
+/*
+ * Allocate and free a "custr_t" dynamic string object. Returns 0 on success
+ * and -1 otherwise.
+ */
+extern int custr_alloc(custr_t **);
+extern void custr_free(custr_t *);
+
+/*
+ * Append a single character, or a NUL-terminated string of characters, to a
+ * dynamic string. Returns 0 on success and -1 otherwise. The dynamic string
+ * will be unmodified if the function returns -1.
+ */
+extern int custr_appendc(custr_t *, char);
+extern int custr_append(custr_t *, const char *);
+
+/*
+ * Determine the length in bytes, not including the NUL terminator, of the
+ * dynamic string.
+ */
+extern size_t custr_len(custr_t *);
+
+/*
+ * Clear the contents of a dynamic string. Does not free the underlying
+ * memory.
+ */
+extern void custr_reset(custr_t *);
+
+/*
+ * Retrieve a const pointer to a NUL-terminated string version of the contents
+ * of the dynamic string. Storage for this string should not be freed, and
+ * the pointer will be invalidated by any mutations to the dynamic string.
+ */
+extern const char *custr_cstr(custr_t *str);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/man/man1/mailx.1 b/usr/src/man/man1/mailx.1
index 671f628c66..cf0cf48337 100644
--- a/usr/src/man/man1/mailx.1
+++ b/usr/src/man/man1/mailx.1
@@ -9,7 +9,7 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH MAILX 1 "Sep 19, 2001"
+.TH MAILX 1 "Dec 18, 2014"
.SH NAME
mailx \- interactive message processing system
.SH SYNOPSIS
@@ -36,7 +36,6 @@ mailx \- interactive message processing system
.fi
.SH DESCRIPTION
-.sp
.LP
The mail utilities listed above provide a comfortable, flexible environment for
sending and receiving mail messages electronically.
@@ -64,7 +63,6 @@ the secondary file can then be read or otherwise processed using the same
\fBCommands\fR as in the primary \fBmailbox\fR. This gives rise within these
pages to the notion of a current \fBmailbox\fR.
.SH OPTIONS
-.sp
.LP
On the command line options start with a dash (\(mi). Any other arguments are
taken to be destinations (recipients). If no recipients are specified,
@@ -294,7 +292,6 @@ Interpret tilde escapes in the input even if not reading from a tty.
.RE
.SH OPERANDS
-.sp
.LP
The following operands are supported:
.sp
@@ -308,7 +305,6 @@ Addressee of message.
.SH USAGE
.SS "Starting Mail"
-.sp
.LP
At startup time, \fBmailx\fR executes the system startup file
\fB/etc/mail/mailx.rc\fR. If invoked as \fBmail\fR or \fBMail\fR, the system
@@ -380,7 +376,6 @@ temporary file. Commands may be entered by beginning a line with the tilde (~)
escape character followed by a single command letter and optional arguments.
See \fBTilde Escapes\fR for a summary of these commands.
.SS "Reading Mail"
-.sp
.LP
Each message is assigned a sequential number, and there is at any time the
notion of a current message, marked by a right angle bracket (>) in the header
@@ -544,21 +539,24 @@ command involved. Filenames, where expected, are expanded using the normal
shell conventions (see \fBsh\fR(1)). Special characters are recognized by
certain commands and are documented with the commands below.
.SS "Sending Mail"
-.sp
.LP
Recipients listed on the command line may be of three types: login names, shell
commands, or alias groups. Login names may be any network address, including
mixed network addressing. If mail is found to be undeliverable, an attempt is
-made to return it to the sender's \fBmailbox\fR. If the recipient name begins
-with a pipe symbol ( | ), the rest of the name is taken to be a shell command
-to pipe the message through. This provides an automatic interface with any
-program that reads the standard input, such as \fBlp\fR(1) for recording
-outgoing mail on paper. Alias groups are set by the \fBa\fRlias command (see
-\fBCommands\fR below) or in a system startup file (for example,
-\fB$HOME/.mailrc\fR). Aliases are lists of recipients of any type.
-.SS "Forwarding Mail"
+made to return it to the sender's \fBmailbox\fR. If the \fBexpandaddr\fR option
+is not set (the default), then the following rules do not apply and the name of
+the recipient must be a local mailbox or network address. If the recipient name
+begins with a pipe symbol ( | ), the rest of the name is taken to be a shell
+command to pipe the message through. This provides an automatic interface with
+any program that reads the standard input, such as \fBlp\fR(1) for recording
+outgoing mail on paper.
.sp
.LP
+Alias groups are set by the \fBa\fRlias command (see \fBCommands\fR below) or in
+a system startup file (for example, \fB$HOME/.mailrc\fR). Aliases are lists of
+recipients of any type.
+.SS "Forwarding Mail"
+.LP
To forward a specific message, include it in a message to the desired
recipients with the \fB~f\fR or \fB~m\fR tilde escapes. See \fBTilde\fR
\fBEscapes\fR below. To forward mail automatically, add a comma-separated list
@@ -569,7 +567,6 @@ must be valid, or the messages will "bounce." You cannot, for instance, reroute
your mail to a new host by forwarding it to your new address if it is not yet
listed in the \fBNIS\fR aliases domain.
.SS "Commands"
-.sp
.LP
Regular commands are of the form
.sp
@@ -768,6 +765,18 @@ ENVIRONMENT VARIABLES). Default editor is \fBed\fR(1).
.sp
.ne 2
.na
+\fB\fBexpandaddr\fR\fR
+.ad
+.sp .6
+.RS 4n
+Causes recipient addresses to be expanded based on the discussion in the section
+\fBSending Mail\fR. Note that enabling this option allows for addresses that can
+cause arbitrary command execution by starting with the \fB|\fR character.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBex\fRit\fR
.ad
.br
@@ -1621,7 +1630,6 @@ Variables\fR).
.RE
.SS "Tilde Escapes"
-.sp
.LP
The following tilde escape commands can be used when composing mail to send.
These may be entered only from \fIinput mode\fR, by beginning a line with the
@@ -1905,7 +1913,6 @@ replaces the message.
.RE
.SS "Internal Variables"
-.sp
.LP
The following variables are internal variables. They may be imported from the
execution environment or set using the \fBse\fRt command at any time. The
@@ -2539,12 +2546,10 @@ the message is not sent.
.RE
.SS "Large File Behavior"
-.sp
.LP
See \fBlargefile\fR(5) for the description of the behavior of \fBmailx\fR when
encountering files greater than or equal to 2 Gbyte ( 2^31 bytes).
.SH ENVIRONMENT VARIABLES
-.sp
.LP
See \fBenviron\fR(5) for descriptions of the following environment variables
that affect the execution of \fBmailx\fR: \fBHOME\fR, \fBLANG\fR,
@@ -2661,7 +2666,6 @@ The name of a preferred screen editor. Default is \fBvi\fR(1).
.RE
.SH EXIT STATUS
-.sp
.LP
When the \fB-e\fR option is specified, the following exit values are returned:
.sp
@@ -2706,7 +2710,6 @@ An error occurred
.RE
.SH FILES
-.sp
.ne 2
.na
\fB\fB$HOME/.mailrc\fR\fR
@@ -2788,7 +2791,6 @@ post office directory
.RE
.SH ATTRIBUTES
-.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
.sp
@@ -2804,7 +2806,6 @@ Interface Stability Standard
.TE
.SH SEE ALSO
-.sp
.LP
\fBbiff\fR(1B), \fBecho\fR(1), \fBed\fR(1), \fBex\fR(1), \fBfmt\fR(1),
\fBlp\fR(1), \fBls\fR(1), \fBmail\fR(1), \fBmail\fR(1B), \fBmailcompat\fR(1),
@@ -2813,7 +2814,6 @@ Interface Stability Standard
\fBpasswd\fR(4), \fBattributes\fR(5), \fBenviron\fR(5), \fBlargefile\fR(5),
\fBstandards\fR(5)
.SH NOTES
-.sp
.LP
Where \fIshell-command\fR is shown as valid, arguments are not always allowed.
Experimentation is recommended.