xref: /illumos-gate/usr/src/cmd/mail/sendlist.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include "mail.h"
32 /*
33  *  NAME
34  *	sendlist - send copy to specified users
35  *
36  *  SYNOPSIS
37  *	int sendlist(reciplist *list, int letnum, int level)
38  *
39  *  DESCRIPTION
40  *	sendlist() will traverse the current recipient list and
41  *	send a copy of the given letter to each user specified,
42  *	invoking send() to do the sending. It returns
43  *	1 if the sending fails, 0 otherwise.
44  */
45 
46 
47 /*
48  * mailx and mailtool read the SENDMAIL from an environment, since few
49  *  people use /bin/mail as their user agent and since /bin/mail is often
50  *  called as root or made setuid it's safer to leave this hardwired.
51  */
52 
53 static char *sendmail_prog = SENDMAIL;
54 
55 static void notifybiff(char *);
56 
57 int
58 sendlist(reciplist *list, int letnum, int level)
59 {
60 	recip *to;
61 	int rc = 0;
62 	FILE *fp;
63 	int nargs = 4;			/* "sendmail", "-oi", "--", .. NULL */
64 	char **argv;
65 	char **p;
66 
67 	/* Deliver mail directly to a mailbox */
68 	if (deliverflag) {
69 		/*
70 		 * Note failure to deliver to any one of the recipients
71 		 * should be considered a failure, so that the user
72 		 * get's an indication of that failure.
73 		 */
74 		for (to = &(list->recip_list); to; to = to->next) {
75 			if (to->name)
76 				if (!send_mbox(to->name, letnum))
77 					rc = 1;
78 		}
79 		return (rc);
80 	}
81 
82 	/*
83 	 * build argv list, allowing for arbitrarily long deliver lists
84 	 * and then  hand the message off to sendmail
85 	 */
86 
87 	if (!ismail)
88 		nargs += 2;	/* for "-f", "Rpath" */
89 
90 	for (to = &(list->recip_list); to; to = to->next)
91 		if (to->name)
92 			nargs++;
93 
94 	argv = malloc(nargs * sizeof (char *));
95 
96 	if (argv == NULL)
97 		return (1);
98 
99 	p = argv;
100 
101 	*p++ = sendmail_prog;
102 
103 	/* If we're rmail add "-f", "Rpath" to the the command line */
104 	if (!ismail) {
105 		*p++ = "-f";
106 		*p++ = Rpath;
107 	}
108 
109 	*p++ = "-oi";
110 	*p++ = "--";		/* extra protection: end of argument list */
111 
112 	for (to = &(list->recip_list); to; to = to->next)
113 		if (to->name)
114 			*p++ = to->name;
115 
116 	*p = NULL;
117 
118 	fp = popenvp(sendmail_prog, argv, "w", 0);
119 
120 	free(argv);
121 
122 	if (fp == NULL)
123 		return (1);
124 
125 	copylet(letnum, fp, ORDINARY);
126 	rc = pclosevp(fp);
127 	if (!rc)
128 		return (0);
129 	else
130 		return (1);
131 }
132 
133 /*
134  * send_mbox(user, letnum)  Sends the letter specified by letnum to the
135  *	"user"'s mailbox. It returns 1 if the sending fails;
136  *	0 on success.
137  */
138 
139 
140 
141 int
142 send_mbox(char *mbox, int letnum)
143 {
144 	char file[PATH_MAX];
145 	char biffmsg[PATH_MAX];
146 	int mbfd;
147 	FILE *malf;
148 	int rc;
149 	uid_t useruid, saved_uid;
150 	void (*istat)(), (*qstat)(), (*hstat)();
151 
152 	if (!islocal(mbox, &useruid))
153 		return (1);
154 	(void) strlcpy(file, maildir, sizeof (file));
155 	if (strlcat(file, mbox, sizeof (file)) >= sizeof (file)) {
156 		rc = FALSE;
157 		goto done;
158 	}
159 
160 	/*
161 	 * We need to setgid and seteuid here since the users's mail box
162 	 * might be NFS mounted and since root can't write across NFS.
163 	 * Note this won't work with Secure NFS/RPC's.  Since delivering to
164 	 * NFS mounted directories isn't really supported that's OK for now.
165 	 */
166 	setgid(mailgrp);
167 	saved_uid = geteuid();
168 	seteuid(useruid);
169 	lock(mbox);
170 
171 	/* ignore signals */
172 	istat = signal(SIGINT, SIG_IGN);
173 	qstat = signal(SIGQUIT, SIG_IGN);
174 	hstat = signal(SIGHUP, SIG_IGN);
175 	/* now access mail box */
176 	mbfd = accessmf(file);
177 	if (mbfd == -1) {	/* mail box access failed, bail out */
178 		unlock();
179 		rc = FALSE;
180 		sav_errno = EACCES;
181 		goto done;
182 	} else {
183 				/* mail box is ok, now do append */
184 		if ((malf = fdopen(mbfd, "a")) != NULL) {
185 			(void) snprintf(biffmsg, sizeof (biffmsg),
186 			    "%s@%d\n", mbox, ftell(malf));
187 			rc = copylet(letnum, malf, ORDINARY);
188 			fclose(malf);
189 		}
190 	}
191 
192 	if (rc == FALSE)
193 		fprintf(stderr, "%s: Cannot append to %s\n", program, file);
194 	else
195 		notifybiff(biffmsg);
196 
197 done:
198 	/* restore signal */
199 	(void) signal(SIGINT, istat);
200 	(void) signal(SIGQUIT, qstat);
201 	(void) signal(SIGHUP, hstat);
202 	unlock();
203 	seteuid(saved_uid);
204 	return (rc);
205 }
206 
207 #include <sys/socket.h>
208 #include <netinet/in.h>
209 
210 static void
211 notifybiff(char *msg)
212 {
213 	static struct sockaddr_in addr;
214 	static int f = -1;
215 
216 	if (addr.sin_family == 0) {
217 		addr.sin_family = AF_INET;
218 		addr.sin_addr.s_addr = INADDR_LOOPBACK;
219 		addr.sin_port = htons(IPPORT_BIFFUDP);
220 	}
221 	if (f < 0)
222 		f = socket(AF_INET, SOCK_DGRAM, 0);
223 	sendto(f, msg, strlen(msg)+1, 0, (struct sockaddr *)&addr,
224 		sizeof (addr));
225 }
226