📄 recipient.c
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)recipient.c 8.44 (Berkeley) 2/28/94";#endif /* not lint */# include "sendmail.h"# include <pwd.h>/*** SENDTOLIST -- Designate a send list.**** The parameter is a comma-separated list of people to send to.** This routine arranges to send to all of them.**** Parameters:** list -- the send list.** ctladdr -- the address template for the person to** send to -- effective uid/gid are important.** This is typically the alias that caused this** expansion.** sendq -- a pointer to the head of a queue to put** these people into.** e -- the envelope in which to add these recipients.**** Returns:** The number of addresses actually on the list.**** Side Effects:** none.*/# define MAXRCRSN 10sendtolist(list, ctladdr, sendq, e) char *list; ADDRESS *ctladdr; ADDRESS **sendq; register ENVELOPE *e;{ register char *p; register ADDRESS *al; /* list of addresses to send to */ bool firstone; /* set on first address sent */ char delimiter; /* the address delimiter */ int naddrs; char *oldto = e->e_to; if (list == NULL) { syserr("sendtolist: null list"); return 0; } if (tTd(25, 1)) { printf("sendto: %s\n ctladdr=", list); printaddr(ctladdr, FALSE); } /* heuristic to determine old versus new style addresses */ if (ctladdr == NULL && (strchr(list, ',') != NULL || strchr(list, ';') != NULL || strchr(list, '<') != NULL || strchr(list, '(') != NULL)) e->e_flags &= ~EF_OLDSTYLE; delimiter = ' '; if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) delimiter = ','; firstone = TRUE; al = NULL; naddrs = 0; for (p = list; *p != '\0'; ) { auto char *delimptr; register ADDRESS *a; /* parse the address */ while ((isascii(*p) && isspace(*p)) || *p == ',') p++; a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); p = delimptr; if (a == NULL) continue; a->q_next = al; a->q_alias = ctladdr; /* see if this should be marked as a primary address */ if (ctladdr == NULL || (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) a->q_flags |= QPRIMARY; if (ctladdr != NULL && sameaddr(ctladdr, a)) ctladdr->q_flags |= QSELFREF; al = a; firstone = FALSE; } /* arrange to send to everyone on the local send list */ while (al != NULL) { register ADDRESS *a = al; al = a->q_next; a = recipient(a, sendq, e); /* arrange to inherit full name */ if (a->q_fullname == NULL && ctladdr != NULL) a->q_fullname = ctladdr->q_fullname; naddrs++; } e->e_to = oldto; return (naddrs);}/*** RECIPIENT -- Designate a message recipient**** Saves the named person for future mailing.**** Parameters:** a -- the (preparsed) address header for the recipient.** sendq -- a pointer to the head of a queue to put the** recipient in. Duplicate supression is done** in this queue.** e -- the current envelope.**** Returns:** The actual address in the queue. This will be "a" if** the address is not a duplicate, else the original address.**** Side Effects:** none.*/ADDRESS *recipient(a, sendq, e) register ADDRESS *a; register ADDRESS **sendq; register ENVELOPE *e;{ register ADDRESS *q; ADDRESS **pq; register struct mailer *m; register char *p; bool quoted = FALSE; /* set if the addr has a quote bit */ int findusercount = 0; char buf[MAXNAME]; /* unquoted image of the user name */ extern int safefile(); e->e_to = a->q_paddr; m = a->q_mailer; errno = 0; if (tTd(26, 1)) { printf("\nrecipient: "); printaddr(a, FALSE); } /* if this is primary, add it to the original recipient list */ if (a->q_alias == NULL) { if (e->e_origrcpt == NULL) e->e_origrcpt = a->q_paddr; else if (e->e_origrcpt != a->q_paddr) e->e_origrcpt = ""; } /* break aliasing loops */ if (AliasLevel > MAXRCRSN) { usrerr("554 aliasing/forwarding loop broken"); return (a); } /* ** Finish setting up address structure. */ /* set the queue timeout */ a->q_timeout = TimeOuts.to_q_return; /* get unquoted user for file, program or user.name check */ (void) strcpy(buf, a->q_user); for (p = buf; *p != '\0' && !quoted; p++) { if (*p == '\\') quoted = TRUE; } stripquotes(buf); /* check for direct mailing to restricted mailers */ if (m == ProgMailer) { if (a->q_alias == NULL) { a->q_flags |= QBADADDR; usrerr("550 Cannot mail directly to programs"); } else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) { a->q_flags |= QBADADDR; usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", a->q_alias->q_ruser, MyHostName); } else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) { a->q_flags |= QBADADDR; usrerr("550 Address %s is unsafe for mailing to programs", a->q_alias->q_paddr); } } /* ** Look up this person in the recipient list. ** If they are there already, return, otherwise continue. ** If the list is empty, just add it. Notice the cute ** hack to make from addresses suppress things correctly: ** the QDONTSEND bit will be set in the send list. ** [Please note: the emphasis is on "hack."] */ for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) { if (sameaddr(q, a)) { if (tTd(26, 1)) { printf("%s in sendq: ", a->q_paddr); printaddr(q, FALSE); } if (!bitset(QPRIMARY, q->q_flags)) { if (!bitset(QDONTSEND, a->q_flags)) message("duplicate suppressed"); q->q_flags |= a->q_flags; } else if (bitset(QSELFREF, q->q_flags)) q->q_flags |= a->q_flags & ~QDONTSEND; a = q; goto testselfdestruct; } } /* add address on list */ *pq = a; a->q_next = NULL; /* ** Alias the name and handle special mailer types. */ trylocaluser: if (tTd(29, 7)) printf("at trylocaluser %s\n", a->q_user); if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) goto testselfdestruct; if (m == InclMailer) { a->q_flags |= QDONTSEND; if (a->q_alias == NULL) { a->q_flags |= QBADADDR; usrerr("550 Cannot mail directly to :include:s"); } else { int ret; message("including file %s", a->q_user); ret = include(a->q_user, FALSE, a, sendq, e); if (transienterror(ret)) {#ifdef LOG if (LogLevel > 2) syslog(LOG_ERR, "%s: include %s: transient error: %s", e->e_id == NULL ? "NOQUEUE" : e->e_id, a->q_user, errstring(ret));#endif a->q_flags |= QQUEUEUP; a->q_flags &= ~QDONTSEND; usrerr("451 Cannot open %s: %s", a->q_user, errstring(ret)); } else if (ret != 0) { a->q_flags |= QBADADDR; usrerr("550 Cannot open %s: %s", a->q_user, errstring(ret)); } } } else if (m == FileMailer) { extern bool writable(); /* check if writable or creatable */ if (a->q_alias == NULL) { a->q_flags |= QBADADDR; usrerr("550 Cannot mail directly to files"); } else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) { a->q_flags |= QBADADDR; usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", a->q_alias->q_ruser, MyHostName); } else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) { a->q_flags |= QBADADDR; usrerr("550 Address %s is unsafe for mailing to files", a->q_alias->q_paddr); } else if (!writable(buf, getctladdr(a), SFF_ANYFILE)) { a->q_flags |= QBADADDR; giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, e); } } if (m != LocalMailer) { if (!bitset(QDONTSEND, a->q_flags)) e->e_nrcpts++; goto testselfdestruct; } /* try aliasing */ alias(a, sendq, e);# ifdef USERDB /* if not aliased, look it up in the user database */ if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags)) { extern int udbexpand(); if (udbexpand(a, sendq, e) == EX_TEMPFAIL) { a->q_flags |= QQUEUEUP; if (e->e_message == NULL) e->e_message = newstr("Deferred: user database error");# ifdef LOG if (LogLevel > 8) syslog(LOG_INFO, "%s: deferred: udbexpand: %s", e->e_id == NULL ? "NOQUEUE" : e->e_id, errstring(errno));# endif message("queued (user database error): %s", errstring(errno)); e->e_nrcpts++; goto testselfdestruct; } }# endif /* if it was an alias or a UDB expansion, just return now */ if (bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags)) goto testselfdestruct; /* ** If we have a level two config file, then pass the name through ** Ruleset 5 before sending it off. Ruleset 5 has the right ** to send rewrite it to another mailer. This gives us a hook ** after local aliasing has been done. */ if (tTd(29, 5)) { printf("recipient: testing local? cl=%d, rr5=%x\n\t", ConfigLevel, RewriteRules[5]); printaddr(a, FALSE); } if (!bitset(QNOTREMOTE, a->q_flags) && ConfigLevel >= 2 && RewriteRules[5] != NULL) { maplocaluser(a, sendq, e); } /* ** If it didn't get rewritten to another mailer, go ahead ** and deliver it. */ if (!bitset(QDONTSEND|QQUEUEUP, a->q_flags)) { auto bool fuzzy; register struct passwd *pw; extern struct passwd *finduser(); /* warning -- finduser may trash buf */ pw = finduser(buf, &fuzzy); if (pw == NULL) { a->q_flags |= QBADADDR; giveresponse(EX_NOUSER, m, NULL, a->q_alias, e); } else { char nbuf[MAXNAME]; if (fuzzy) { /* name was a fuzzy match */ a->q_user = newstr(pw->pw_name); if (findusercount++ > 3) { a->q_flags |= QBADADDR; usrerr("554 aliasing/forwarding loop for %s broken", pw->pw_name); return (a); } /* see if it aliases */ (void) strcpy(buf, pw->pw_name); goto trylocaluser; } if (strcmp(pw->pw_dir, "/") == 0) a->q_home = ""; else a->q_home = newstr(pw->pw_dir); a->q_uid = pw->pw_uid; a->q_gid = pw->pw_gid; a->q_ruser = newstr(pw->pw_name); a->q_flags |= QGOODUID; buildfname(pw->pw_gecos, pw->pw_name, nbuf); if (nbuf[0] != '\0') a->q_fullname = newstr(nbuf); if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && !usershellok(pw->pw_shell)) { a->q_flags |= QBOGUSSHELL; } if (!quoted) forward(a, sendq, e); } } if (!bitset(QDONTSEND, a->q_flags)) e->e_nrcpts++; testselfdestruct: if (tTd(26, 8)) { printf("testselfdestruct: "); printaddr(a, TRUE); } if (a->q_alias == NULL && a != &e->e_from && bitset(QDONTSEND, a->q_flags)) { q = *sendq; while (q != NULL && bitset(QDONTSEND, q->q_flags)) q = q->q_next; if (q == NULL) { a->q_flags |= QBADADDR; usrerr("554 aliasing/forwarding loop broken"); } } return (a);}/*** FINDUSER -- find the password entry for a user.**** This looks a lot like getpwnam, except that it may want to** do some fancier pattern matching in /etc/passwd.**** This routine contains most of the time of many sendmail runs.** It deserves to be optimized.**** Parameters:** name -- the name to match against.** fuzzyp -- an outarg that is set to TRUE if this entry** was found using the fuzzy matching algorithm;** set to FALSE otherwise.**** Returns:** A pointer to a pw struct.** NULL if name is unknown or ambiguous.**** Side Effects:** may modify name.*/struct passwd *finduser(name, fuzzyp) char *name; bool *fuzzyp;{ register struct passwd *pw; register char *p; extern struct passwd *getpwent(); extern struct passwd *getpwnam(); if (tTd(29, 4)) printf("finduser(%s): ", name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -