root/usr/src/cmd/mail/main.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (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]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */

#include "mail.h"
#ifdef SVR4
#include <locale.h>
#endif
/*
 *      mail [ -ehpPqrtw ] [-x debuglevel] [ -f file ] [ -F user(s) ]
 *      mail -T file persons
 *      mail [ -tw ] [ -m messagetype ] persons
 *      rmail [ -tw ] persons
 */
int
main(int argc, char **argv)
{
        register int i;
        char *cptr, *p;
        struct stat statb;
        static char pn[] = "main";
        extern char **environ;
        int env_var_idx, next_slot_idx;
        int tmpfd = -1;

#ifdef SVR4
        (void) setlocale(LC_ALL, "");
#endif
        /* fix here for bug #1086130 - security hole    */
        /* skip over the LD_* env variable              */
        env_var_idx = 0; next_slot_idx = 0;
        while (environ[env_var_idx] != NULL) {
                        environ[next_slot_idx] = environ[env_var_idx];
                if (strncmp(environ[env_var_idx], "LD_", 3)) {
                        next_slot_idx++;
                }
                env_var_idx++;
        }
        environ[next_slot_idx] = NULL;

#ifdef SIGCONT
#ifdef SVR4
        {
        struct sigaction nsig;
        nsig.sa_handler = SIG_DFL;
        sigemptyset(&nsig.sa_mask);
        nsig.sa_flags = SA_RESTART;
        (void) sigaction(SIGCONT, &nsig, (struct sigaction *)0);
        }
#else
        sigset(SIGCONT, SIG_DFL);
#endif
#endif

        /*
         *      Strip off path name of this command for use in messages
         */
        if ((program = strrchr(argv[0], '/')) != NULL) {
                program++;
        } else {
                program = argv[0];
        }

        /* Close all file descriptors except stdin, stdout & stderr */
        closefrom(STDERR_FILENO + 1);

        /*
         *      Get group id for mail, exit if none exists
         */
        if ((grpptr = getgrnam("mail")) == NULL) {
                errmsg(E_GROUP, "");
                exit(1);
        } else {
                mailgrp = grpptr->gr_gid;
        }

        /*
         *      Save the *id for later use.
         */
        my_uid = getuid();
        my_gid = getgid();
        my_euid = geteuid();
        my_egid = getegid();

        /*
         *      What command (rmail or mail)?
         */
        if (strcmp(program, "rmail") == SAME) {
                ismail = FALSE;
        }

        /*
         *      Parse the command line and adjust argc and argv
         *      to compensate for any options
         */
        i = parse(argc, argv);
        argv += (i - 1);
        argc -= (i - 1);

        /* block a potential security hole */
        if (flgT && (my_euid != 0)) {
                setgid(my_gid);
                Tout(pn, "Setgid unset\n");
        }

        if (debug == 0) {
                /* If not set as an invocation option, check for system-wide */
                /* global flag */
                char *xp = xgetenv("DEBUG");
                if (xp != (char *)NULL) {
                        debug = atoi(xp);
                        if (debug < 0) {
                                /* Keep trace file even if successful */
                                keepdbgfile = -1;
                                debug = -debug;
                        }
                }
        }
        if (debug > 0) {
                strcpy(dbgfname, "/tmp/MLDBGXXXXXX");
                if ((tmpfd = mkstemp(dbgfname)) == -1) {
                        fprintf(stderr, "%s: can't open debugging file '%s'\n",
                                program, dbgfname);
                        exit(13);
                }
                if ((dbgfp = fdopen(tmpfd, "w")) == (FILE *)NULL) {
                        fprintf(stderr, "%s: can't open debugging file '%s'\n",
                                program, dbgfname);
                        (void) close(tmpfd);
                        exit(13);
                }
                setbuf(dbgfp, NULL);
                fprintf(dbgfp, "main(): debugging level == %d\n", debug);
                fprintf(dbgfp, "main(): trace file ='%s': kept %s\n", dbgfname,
                        ((keepdbgfile < 0) ?
                                "on success or failure." : "only on failure."));
        }

        if (!ismail && (goerr > 0 || !i)) {
                Dout(pn, 11, "!ismail, goerr=%d, i=%d\n", goerr, i);
                if (goerr > 0) {
                        errmsg(E_SYNTAX, "Usage: rmail [-wt] person(s)");
                }
                if (!i) {
                        errmsg(E_SYNTAX, "At least one user must be specified");
                }
                Dout(pn, 11, "exiting!\n");
                done(0);
        }

        umsave = umask(7);
        uname(&utsn);
        if ((p = xgetenv("CLUSTER")) != (char *)NULL) {
                /*
                 * We are not who we appear...
                 */
                thissys = p;
        } else {
                thissys = utsn.nodename;
        }
        Dout(pn, 11, "thissys = '%s', uname = '%s'\n", thissys, utsn.nodename);

        failsafe = xgetenv("FAILSAFE");
        if (failsafe)
                Dout(pn, 11, "failsafe processing enabled to %s\n", failsafe);

        /*
         *      Use environment variables
         */
        home = getenv("HOME");
        if (!home || !*home) {
                home = ".";
        }

        my_name[0] = '\0';
        pwd = getpwuid(my_uid);
        if (pwd)
                (void) strlcpy(my_name, pwd->pw_name, sizeof (my_name));

        /* If root, use LOGNAME if set */
        if (my_uid == 0) {
                /* If root, use LOGNAME if set */
                if (((cptr = getenv("LOGNAME")) != NULL) &&
                    (strlen(cptr) != 0)) {
                        (void) strlcpy(my_name, cptr, sizeof (my_name));
                }
        }
        Dout(pn, 11, "my_name = '%s'\n", my_name);

        /*
         *      Catch signals for cleanup
         */
        if (setjmp(sjbuf)) {
                done(0);
        }
        for (i = SIGINT; i < SIGCLD; i++) {
                setsig(i, delete);
        }
        setsig(SIGHUP, sig_done);
        setsig(SIGTERM, sig_done);

        cksaved(my_name);

        /*
         *      Rmail is always invoked to send mail
         */
        Dout(pn, 11, "ismail=%d, argc=%d\n", ismail, argc);
        if (ismail && (argc == 1)) {
                sending = FALSE;
                printmail();

        } else {
                sending = TRUE;
                sendmail(argc, argv);
        }
        done(0);
}