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