5481 CVE-2012-1750 mailx(1) tilde expansion vulnerability
[illumos-gate.git] / usr / src / cmd / mailx / main.c
blob0271552beae7fd25266fa7156bb7b29c07ef300b
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
40 #include "rcv.h"
41 #ifndef preSVr4
42 #include <locale.h>
43 #endif
46 * mailx -- a modified version of a University of California at Berkeley
47 * mail program
49 * Startup -- interface with user.
52 static void hdrstop(int);
54 static jmp_buf hdrjmp;
56 const char *const version = "mailx version 5.0";
59 * Find out who the user is, copy his mail file (if exists) into
60 * /tmp/Rxxxxx and set up the message pointers. Then, print out the
61 * message headers and read user commands.
63 * Command line syntax:
64 * mailx [ -i ] [ -r address ] [ -h number ] [ -f [ name ] ]
65 * or:
66 * mailx [ -i ] [ -r address ] [ -h number ] people ...
68 * and a bunch of other options.
71 int
72 main(int argc, char **argv)
74 register char *ef;
75 register int argp;
76 int mustsend, f, goerr = 0;
77 void (*prevint)(int);
78 int loaded = 0;
79 struct termio tbuf;
80 struct termios tbufs;
81 int c;
82 char *cwd, *mf;
85 * Set up a reasonable environment.
86 * Figure out whether we are being run interactively, set up
87 * all the temporary files, buffer standard output, and so forth.
90 #ifndef preSVr4
91 (void)setlocale(LC_ALL, "");
92 #endif
93 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
94 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
95 #endif
96 (void) textdomain(TEXT_DOMAIN);
98 #ifdef SIGCONT
99 sigset(SIGCONT, SIG_DFL);
100 #endif
101 rpterr = 0; /* initialize; set when we output to stderr */
102 progname = argv[0];
103 if (progname[strlen(progname) - 1] != 'x') {
104 assign("bsdcompat", "");
106 myegid = getegid();
107 myrgid = getgid();
108 myeuid = geteuid();
109 myruid = getuid();
110 mypid = getpid();
111 setgid(myrgid);
112 setuid(myruid);
113 inithost();
114 intty = isatty(0);
115 if (ioctl(1, TCGETS, &tbufs) < 0) {
116 if (ioctl(1, TCGETA, &tbuf)==0) {
117 outtty = 1;
118 baud = tbuf.c_cflag & CBAUD;
119 } else
120 baud = B9600;
121 } else {
122 outtty = 1;
123 baud = cfgetospeed(&tbufs);
125 image = -1;
128 * Now, determine how we are being used.
129 * We successively pick off instances of -r, -h, -f, and -i.
130 * If called as "rmail" we note this fact for letter sending.
131 * If there is anything left, it is the base of the list
132 * of users to mail to. Argp will be set to point to the
133 * first of these users.
136 ef = NOSTR;
137 argp = -1;
138 mustsend = 0;
139 if (argc > 0 && **argv == 'r')
140 rmail++;
141 while ((c = getopt(argc, argv, "b:Bc:defFh:HiInNr:s:u:UtT:vV~")) != EOF)
142 switch (c) {
143 case 'e':
145 * exit status only
147 exitflg++;
148 break;
150 case 'r':
152 * Next argument is address to be sent along
153 * to the mailer.
155 mustsend++;
156 rflag = optarg;
157 break;
159 case 'T':
161 * Next argument is temp file to write which
162 * articles have been read/deleted for netnews.
164 Tflag = optarg;
165 if ((f = creat(Tflag, TEMPPERM)) < 0) {
166 perror(Tflag);
167 exit(1);
169 close(f);
170 /* fall through for -I too */
171 /* FALLTHROUGH */
173 case 'I':
175 * print newsgroup in header summary
177 newsflg++;
178 break;
180 case 'u':
182 * Next argument is person's mailbox to use.
183 * Treated the same as "-f /var/mail/user".
186 static char u[PATHSIZE];
187 snprintf(u, sizeof (u), "%s%s", maildir, optarg);
188 ef = u;
189 break;
192 case 'i':
194 * User wants to ignore interrupts.
195 * Set the variable "ignore"
197 assign("ignore", "");
198 break;
200 case 'U':
201 UnUUCP++;
202 break;
204 case 'd':
205 assign("debug", "");
206 break;
208 case 'h':
210 * Specified sequence number for network.
211 * This is the number of "hops" made so
212 * far (count of times message has been
213 * forwarded) to help avoid infinite mail loops.
215 mustsend++;
216 hflag = atoi(optarg);
217 if (hflag == 0) {
218 fprintf(stderr,
219 gettext("-h needs non-zero number\n"));
220 goerr++;
222 break;
224 case 's':
226 * Give a subject field for sending from
227 * non terminal
229 mustsend++;
230 sflag = optarg;
231 break;
233 case 'c': /* Cc: from command line */
234 mustsend++;
235 cflag = optarg;
236 break;
238 case 'b': /* Bcc: from command line */
239 mustsend++;
240 bflag = optarg;
241 break;
243 case 'f':
245 * User is specifying file to "edit" with mailx,
246 * as opposed to reading system mailbox.
247 * If no argument is given after -f, we read his/her
248 * $MBOX file or mbox in his/her home directory.
250 ef = (argc == optind || *argv[optind] == '-')
251 ? "" : argv[optind++];
252 if (*ef && *ef != '/' && *ef != '+')
253 cwd = getcwd(NOSTR, PATHSIZE);
254 break;
256 case 'F':
257 Fflag++;
258 mustsend++;
259 break;
261 case 'n':
263 * User doesn't want to source
264 * /etc/mail/mailx.rc
266 nosrc++;
267 break;
269 case 'N':
271 * Avoid initial header printing.
273 noheader++;
274 break;
276 case 'H':
278 * Print headers and exit
280 Hflag++;
281 break;
283 case 'V':
284 puts(version);
285 return 0;
287 case '~':
289 * Permit tildas no matter where
290 * the input is coming from.
292 assign("escapeok", "");
293 break;
295 case 'v':
297 * Send mailer verbose flag
299 assign("verbose", "");
300 break;
302 case 'B':
304 * Don't buffer output
305 * (Line buffered is good enough)
307 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
308 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
309 break;
311 case 't':
313 * Like sendmail -t, read headers from text
315 tflag++;
316 mustsend++;
317 break;
319 case '?':
320 default:
321 goerr++;
322 break;
325 if (optind != argc)
326 argp = optind;
329 * Check for inconsistent arguments.
332 if (newsflg && ef==NOSTR) {
333 fprintf(stderr, gettext("Need -f with -I flag\n"));
334 goerr++;
336 if (ef != NOSTR && argp != -1) {
337 fprintf(stderr,
338 gettext("Cannot give -f and people to send to.\n"));
339 goerr++;
341 if (exitflg && (mustsend || argp != -1))
342 exit(1); /* nonsense flags involving -e simply exit */
343 if (tflag && argp != -1) {
344 fprintf(stderr,
345 gettext("Ignoring recipients on command line with -t\n"));
346 argp = -1;
347 } else if (!tflag && mustsend && argp == -1) {
348 fprintf(stderr,
349 gettext("The flags you gave are used only when sending mail.\n"));
350 goerr++;
352 if (goerr) {
353 fprintf(stderr,
354 gettext("Usage: %s -eiIUdFntBNHvV~ -T FILE -u USER -h hops -r address\n"),
355 progname);
356 fprintf(stderr,
357 gettext("\t\t-s SUBJECT -f FILE users\n"));
358 exit(1);
360 tinit();
361 input = stdin;
362 rcvmode = !tflag && argp == -1;
363 if (!nosrc)
364 load(MASTER);
366 if (!rcvmode) {
367 load(Getf("MAILRC"));
368 if (tflag)
369 tmail();
370 else
371 mail(&argv[argp]);
372 exit(senderr ? senderr : rpterr);
376 * Ok, we are reading mail.
377 * Decide whether we are editing a mailbox or reading
378 * the system mailbox, and open up the right stuff.
380 * Do this before sourcing the MAILRC, because there might be
381 * a 'chdir' there that breaks the -f option. But if the
382 * file specified with -f is a folder name, go ahead and
383 * source the MAILRC anyway so that "folder" will be defined.
386 nstrcpy(origname, PATHSIZE, mailname);
387 editfile = mailname;
389 if (ef != NOSTR) {
390 if (ef == NOSTR || *ef == '\0' || *ef == '+') {
391 load(Getf("MAILRC"));
392 loaded++;
394 ef = *ef ? safeexpand(ef) : Getf("MBOX");
395 nstrcpy(origname, PATHSIZE, ef);
396 if (ef[0] != '/') {
397 if (cwd == NOSTR)
398 cwd = getcwd(NOSTR, PATHSIZE);
399 nstrcat(cwd, PATHSIZE, "/");
400 nstrcat(cwd, PATHSIZE, ef);
401 ef = cwd;
403 editfile = ef;
404 edit++;
407 if (setfile(editfile, edit) < 0)
408 exit(1);
410 if (!loaded)
411 load(Getf("MAILRC"));
412 if (msgCount > 0 && !noheader && value("header") != NOSTR) {
413 if (setjmp(hdrjmp) == 0) {
414 if ((prevint = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
415 sigset(SIGINT, hdrstop);
416 announce();
417 fflush(stdout);
418 sigset(SIGINT, prevint);
421 if (Hflag || (!edit && msgCount == 0)) {
422 if (!Hflag) {
423 fprintf(stderr, gettext("No mail for %s\n"), myname);
424 Verhogen();
426 fflush(stdout);
427 exit(rpterr);
429 commands();
430 sigset(SIGHUP, SIG_IGN);
431 sigset(SIGINT, SIG_IGN);
432 sigset(SIGQUIT, SIG_IGN);
433 if (!outtty)
434 sigset(SIGPIPE, SIG_IGN);
435 if (edit)
436 edstop(0);
437 else {
438 quit(0);
439 Verhogen();
441 return (rpterr);
445 * Interrupt printing of the headers.
447 static void
448 #ifdef __cplusplus
449 hdrstop(int)
450 #else
451 /* ARGSUSED */
452 hdrstop(int s)
453 #endif
456 fflush(stdout);
457 fprintf(stderr, gettext("\nInterrupt\n"));
458 # ifdef OLD_BSD_SIGS
459 sigrelse(SIGINT);
460 # endif
461 longjmp(hdrjmp, 1);