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); }
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); }