sendlist.c revision b7d62af5b42f0da2eb668e8d33d24d2f4fdd98a8
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
53static char *sendmail_prog = SENDMAIL;
54
55static void notifybiff(char *);
56
57int
58sendlist(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
141int
142send_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
197done:
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
210static void
211notifybiff(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