Exemple #1
0
int
send_mbox(char *mbox, int letnum)
{
	char file[PATH_MAX];
	char biffmsg[PATH_MAX];
	int mbfd;
	FILE *malf;
	int rc;
	uid_t useruid, saved_uid;
	void (*istat)(), (*qstat)(), (*hstat)();

	if (!islocal(mbox, &useruid))
		return (1);
	(void) strlcpy(file, maildir, sizeof (file));
	if (strlcat(file, mbox, sizeof (file)) >= sizeof (file)) {
		rc = FALSE;
		goto done;
	}

	/*
	 * We need to setgid and seteuid here since the users's mail box
	 * might be NFS mounted and since root can't write across NFS.
	 * Note this won't work with Secure NFS/RPC's.  Since delivering to
	 * NFS mounted directories isn't really supported that's OK for now.
	 */
	setgid(mailgrp);
	saved_uid = geteuid();
	seteuid(useruid);
	lock(mbox);

	/* ignore signals */
	istat = signal(SIGINT, SIG_IGN);
	qstat = signal(SIGQUIT, SIG_IGN);
	hstat = signal(SIGHUP, SIG_IGN);
	/* now access mail box */
	mbfd = accessmf(file);
	if (mbfd == -1) {	/* mail box access failed, bail out */
		unlock();
		rc = FALSE;
		sav_errno = EACCES;
		goto done;
	} else {
				/* mail box is ok, now do append */
		if ((malf = fdopen(mbfd, "a")) != NULL) {
			(void) snprintf(biffmsg, sizeof (biffmsg),
			    "%s@%d\n", mbox, ftell(malf));
			rc = copylet(letnum, malf, ORDINARY);
			fclose(malf);
		}
	}

	if (rc == FALSE)
		fprintf(stderr, "%s: Cannot append to %s\n", program, file);
	else
		notifybiff(biffmsg);

done:
	/* restore signal */
	(void) signal(SIGINT, istat);
	(void) signal(SIGQUIT, qstat);
	(void) signal(SIGHUP, hstat);
	unlock();
	seteuid(saved_uid);
	return (rc);
}
Exemple #2
0
int
deliver(int fd, char *name, int lockfile)
{
	struct stat sb, fsb;
	struct passwd *pw;
	int mbfd=-1, rval=1, lfd=-1;
	char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
	off_t curoff;
	size_t off;
	ssize_t nr, nw;

	/*
	 * Disallow delivery to unknown names -- special mailboxes can be
	 * handled in the sendmail aliases file.
	 */
	if (!(pw = getpwnam(name))) {
		merr(NOTFATAL, "unknown name: %s", name);
		return(1);
	}

	(void)snprintf(path, sizeof path, "%s/%s", _PATH_MAILDIR, name);

	if (lockfile) {
		lfd = getlock(name, pw);
		if (lfd == -1)
			return (1);
	}

	/* after this point, always exit via bad to remove lockfile */
retry:
	if (lstat(path, &sb)) {
		if (errno != ENOENT) {
			merr(NOTFATAL, "%s: %s", path, strerror(errno));
			goto bad;
		}
		if ((mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|O_EXLOCK,
		    S_IRUSR|S_IWUSR)) < 0) {
			if (errno == EEXIST) {
				/* file appeared since lstat */
				goto retry;
			} else {
				merr(NOTFATAL, "%s: %s", path, strerror(errno));
				goto bad;
			}
		}
		/*
		 * Set the owner and group.  Historically, binmail repeated
		 * this at each mail delivery.  We no longer do this, assuming
		 * that if the ownership or permissions were changed there
		 * was a reason for doing so.
		 */
		if (fchown(mbfd, pw->pw_uid, pw->pw_gid) < 0) {
			merr(NOTFATAL, "chown %u:%u: %s",
			    pw->pw_uid, pw->pw_gid, name);
			goto bad;
		}
	} else {
		if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) {
			merr(NOTFATAL, "%s: linked or special file", path);
			goto bad;
		}
		if ((mbfd = open(path, O_APPEND|O_WRONLY|O_EXLOCK,
		    S_IRUSR|S_IWUSR)) < 0) {
			merr(NOTFATAL, "%s: %s", path, strerror(errno));
			goto bad;
		}
		if (fstat(mbfd, &fsb)) {
			/* relating error to path may be bad style */
			merr(NOTFATAL, "%s: %s", path, strerror(errno));
			goto bad;
		}
		if (sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino) {
			merr(NOTFATAL, "%s: changed after open", path);
			goto bad;
		}
		/* paranoia? */
		if (fsb.st_nlink != 1 || !S_ISREG(fsb.st_mode)) {
			merr(NOTFATAL, "%s: linked or special file", path);
			goto bad;
		}
	}

	curoff = lseek(mbfd, 0, SEEK_END);
	(void)snprintf(biffmsg, sizeof biffmsg, "%s@%qd\n", name, curoff);
	if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
		merr(NOTFATAL, "temporary file: %s", strerror(errno));
		goto bad;
	}

	while ((nr = read(fd, buf, sizeof(buf))) > 0)
		for (off = 0; off < nr;  off += nw)
			if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
				merr(NOTFATAL, "%s: %s", path, strerror(errno));
				(void)ftruncate(mbfd, curoff);
				goto bad;
			}

	if (nr == 0) {
		rval = 0;
	} else {
		(void)ftruncate(mbfd, curoff);
		merr(FATAL, "temporary file: %s", strerror(errno));
	}

bad:
	if (lfd != -1) {
		rellock();
		close(lfd);
	}

	if (mbfd != -1) {
		(void)fsync(mbfd);		/* Don't wait for update. */
		(void)close(mbfd);		/* Implicit unlock. */
	}

	if (!rval)
		notifybiff(biffmsg);
	return(rval);
}