1N/A * Copyright (c) 1998-2003, 2006 Sendmail, Inc. and its suppliers. 1N/A * All rights reserved. 1N/A * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 1N/A * Copyright (c) 1988, 1993 1N/A * The Regents of the University of California. All rights reserved. 1N/A * By using this file, you agree to the terms and conditions set 1N/A * forth in the LICENSE file which can be found at the top level of 1N/A * the sendmail distribution. 1N/A#
pragma ident "%Z%%M% %I% %E% SMI" 1N/A** SORTHOST -- strcmp()-like func for host portion of an ADDRESS 1N/A** xx -- first ADDRESS 1N/A** yy -- second ADDRESS 1N/A** <0 when xx->q_host is less than yy->q_host 1N/A** >0 when xx->q_host is greater than yy->q_host 1N/A /* XXX maybe compare hostnames from the end? */ 1N/A#
else /* _FFR_HOST_SORT_REVERSE */ 1N/A#
endif /* _FFR_HOST_SORT_REVERSE */ 1N/A** SORTEXPENSIVE -- strcmp()-like func for expensive mailers 1N/A** The mailer has been noted already as "expensive" for 'xx'. This 1N/A** will give a result relative to 'yy'. Expensive mailers get rated 1N/A** "greater than" non-expensive mailers because during the delivery phase 1N/A** it will get queued -- no use it getting in the way of less expensive 1N/A** recipients. We avoid an MX RR lookup when both 'xx' and 'yy' are 1N/A** expensive since an MX RR lookup happens when extracted from the queue 1N/A** xx -- first ADDRESS 1N/A** yy -- second ADDRESS 1N/A** <0 when xx->q_host is less than yy->q_host and both are 1N/A** >0 when xx->q_host is greater than yy->q_host, or when 1N/A** 'yy' is non-expensive 1N/A** 0 when equal (by expense and q_host) 1N/A return 1;
/* xx should go later */ 1N/A /* XXX maybe compare hostnames from the end? */ 1N/A#
else /* _FFR_HOST_SORT_REVERSE */ 1N/A#
endif /* _FFR_HOST_SORT_REVERSE */ 1N/A** SORTBYSIGNATURE -- a strcmp()-like func for q_mailer and q_host in ADDRESS 1N/A** xx -- first ADDRESS 1N/A** yy -- second ADDRESS 1N/A** 0 when the "signature"'s are same 1N/A** <0 when xx->q_signature is less than yy->q_signature 1N/A** >0 when xx->q_signature is greater than yy->q_signature 1N/A** May set ADDRESS pointer for q_signature if not already set. 1N/A /* Let's avoid redoing the signature over and over again */ 1N/A ** If the two signatures are the same then we will return a sort 1N/A ** value based on 'q_user'. But note that we have reversed xx and yy 1N/A ** on purpose. This additional compare helps reduce the number of 1N/A ** sameaddr() calls and loops in recipient() for the case when 1N/A ** the rcpt list has been provided already in-order. 1N/A** SENDTOLIST -- Designate a send list. 1N/A** The parameter is a comma-separated list of people to send to. 1N/A** This routine arranges to send to all of them. 1N/A** list -- the send list. 1N/A** ctladdr -- the address template for the person to 1N/A** send to -- effective uid/gid are important. 1N/A** This is typically the alias that caused this 1N/A** sendq -- a pointer to the head of a queue to put 1N/A** these people into. 1N/A** aliaslevel -- the current alias nesting depth -- to 1N/A** e -- the envelope in which to add these recipients. 1N/A** The number of addresses actually on the list. 1N/A/* q_flags bits inherited from ctladdr */ 1N/A /* heuristic to determine old versus new style addresses */ 1N/A /* make sure we have enough space to copy the string */ 1N/A /* parse the address */ 1N/A /* arrange to inherit attributes from parent */ 1N/A /* self reference test */ 1N/A /* check for address loops */ 1N/A /* various flag bits */ 1N/A /* DSN recipient information */ 1N/A /* arrange to send to everyone on the local send list */ 1N/A** REMOVEFROMLIST -- Remove addresses from a send list. 1N/A** The parameter is a comma-separated list of recipients to remove. 1N/A** Note that it only deletes matching addresses. If those addresses 1N/A** have been expanded already in the sendq, it won't mark the 1N/A** expanded recipients as QS_REMOVED. 1N/A** list -- the list to remove. 1N/A** sendq -- a pointer to the head of a queue to remove 1N/A** these addresses from. 1N/A** e -- the envelope in which to remove these recipients. 1N/A** The number of addresses removed from the list. 1N/A /* heuristic to determine old versus new style addresses */ 1N/A /* make sure we have enough space to copy the string */ 1N/A#
endif /* _FFR_ADDR_TYPE_MODES */ 1N/A /* parse the address */ 1N/A** RECIPIENT -- Designate a message recipient 1N/A** Saves the named person for future mailing (after some checks). 1N/A** new -- the (preparsed) address header for the recipient. 1N/A** sendq -- a pointer to the head of a queue to put the 1N/A** recipient in. Duplicate suppression is done 1N/A** aliaslevel -- the current alias nesting depth. 1N/A** e -- the current envelope. 1N/A** The actual address in the queue. This will be "a" if 1N/A** the address is not a duplicate, else the original address. 1N/A bool quoted;
/* set if the addr has a quote bit */ 1N/A /* if this is primary, use it as original recipient */ 1N/A /* find parent recipient for finalrcpt and orcpt */ 1N/A /* find final recipient DSN address */ 1N/A /* strip brackets from address */ 1N/A "%s; %.700s@%.100s",
1N/A /* set ORCPT DSN arg if not already set */ 1N/A /* check for an existing ORCPT */ 1N/A /* FFR: Needs to strip comments from stdin addrs */ 1N/A /* strip brackets from address */ 1N/A /* if too big, don't use it */ 1N/A#
endif /* _FFR_GEN_ORCPT */ 1N/A /* break aliasing loops */ 1N/A ** Finish setting up address structure. 1N/A /* get unquoted user for file, program or user.name check */ 1N/A /* check for direct mailing to restricted mailers */ 1N/A "550 Cannot mail directly to programs");
1N/A "550 UID %d is an unknown user: cannot mail to programs",
1N/A "550 User %s@%s doesn't have a valid shell for mailing to programs",
1N/A "550 Address %s is unsafe for mailing to programs",
1N/A ** Look up this person in the recipient list. 1N/A ** If they are there already, return, otherwise continue. 1N/A ** If the list is empty, just add it. Notice the cute 1N/A ** hack to make from addresses suppress things correctly: 1N/A ** the QS_DUPLICATE state will be set in the send list. 1N/A ** [Please note: the emphasis is on "hack."] 1N/A ** If this message is going to the queue or FastSplit is set 1N/A ** and it is the first try and the envelope hasn't split, then we 1N/A ** avoid doing an MX RR lookup now because one will be done when the 1N/A ** message is extracted from the queue later. It can go to the queue 1N/A ** because all messages are going to the queue or this mailer of 1N/A ** the current recipient is marked expensive. 1N/A ** If address is "less than" it should be inserted now. 1N/A ** If address is "greater than" current comparison it'll 1N/A ** insert later in the list; so loop again (if possible). 1N/A ** If address is "equal" (different equal than sameaddr() 1N/A ** call) then check if sameaddr() will be true. 1N/A ** Because this list is now sorted, it'll mean fewer 1N/A ** comparisons and fewer loops which is important for more 1N/A if (i == 0)
/* equal */ 1N/A ** Sortbysignature() has said that the two have 1N/A ** equal MX RR's and the same user. Calling sameaddr() 1N/A ** now checks if the two hosts are as identical as the 1N/A ** MX RR's are (which might not be the case) 1N/A ** before saying these are the identical addresses. 1N/A ** If an earlier milter removed the 1N/A ** address, a later one can still add 1N/A else if (i < 0)
/* less than */ 1N/A /* pq should point to an address, never NULL */ 1N/A /* add address on list */ 1N/A ** insert before 'pq'. Only possible when at least 1 1N/A ** ADDRESS is in the list already. 1N/A ** Place in list at current 'pq' position. Possible 1N/A ** when there are 0 or more ADDRESS's in the list. 1N/A /* added a new address: clear split flag */ 1N/A ** Alias the name and handle special mailer types. 1N/A "550 Cannot mail directly to :include:s");
1N/A "include %s: transient error: %s",
1N/A "550 Cannot open %s: %s",
1N/A /* check if allowed */ 1N/A "550 Cannot mail directly to files");
1N/A "550 UID %d is an unknown user: cannot mail to files",
1N/A "550 User %s@%s doesn't have a valid shell for mailing to files",
1N/A "550 Address %s is unsafe for mailing to files",
1N/A /* if not aliased, look it up in the user database */ 1N/A "Deferred: user database error");
1N/A "deferred: udbexpand: %s",
1N/A ** If we have a level two config file, then pass the name through 1N/A ** Ruleset 5 before sending it off. Ruleset 5 has the right 1N/A ** to rewrite it to another mailer. This gives us a hook 1N/A ** after local aliasing has been done. 1N/A ** If it didn't get rewritten to another mailer, go ahead 1N/A /* warning -- finduser may trash buf */ 1N/A /* name was a fuzzy match */ 1N/A /* see if it aliases */ 1N/A /* don't do any more now */ 1N/A ** If we are at the top level, check to see if this has 1N/A ** expanded to exactly one address. If so, it can inherit 1N/A ** the primaryness of the address. 1N/A ** While we're at it, clear the QTHISPASS bits. 1N/A /* check to see if this actually got a new owner */ 1N/A /* arrange for return receipt */ 1N/A "%s... expanded to multiple addresses\n",
1N/A** FINDUSER -- find the password entry for a user. 1N/A** This looks a lot like getpwnam, except that it may want to 1N/A** This routine contains most of the time of many sendmail runs. 1N/A** It deserves to be optimized. 1N/A** name -- the name to match against. 1N/A** fuzzyp -- an outarg that is set to true if this entry 1N/A** was found using the fuzzy matching algorithm; 1N/A** set to false otherwise. 1N/A** user -- structure to fill in if user is found 1N/A** On success, fill in *user, set *fuzzyp and return EX_OK. 1N/A** If the user was not found, return EX_NOUSER. 1N/A** On error, return EX_TEMPFAIL or EX_OSERR. 1N/A#
endif /* MATCHGECOS */ 1N/A /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 1N/A /* look up this login name using fast path */ 1N/A /* try mapping it to lower case */ 1N/A /* see if fuzzy matching allowed */ 1N/A /* search for a matching full name instead */ 1N/A#
endif /* DEC_OSF_BROKEN_GETPWENT */ 1N/A#
else /* MATCHGECOS */ 1N/A#
endif /* MATCHGECOS */ 1N/A** WRITABLE -- predicate returning if the file is writable. 1N/A** This routine must duplicate the algorithm in sys/fio.c. 1N/A** Unfortunately, we cannot use the access call since we 1N/A** won't necessarily be the real uid when we try to 1N/A** actually open the file. 1N/A** Notice that ANY file with ANY execute bit is automatically 1N/A** not writable. This is also enforced by mailfile. 1N/A** filename -- the file name to check. 1N/A** ctladdr -- the controlling address for this file. 1N/A** flags -- SFF_* flags to control the function. 1N/A** true -- if we will be able to write this file. 1N/A** false -- if we cannot write this file. 1N/A ** File does exist -- check that it is writable. 1N/A** INCLUDE -- handle :include: specification. 1N/A** fname -- filename to include. 1N/A** forwarding -- if true, we are reading a .forward file. 1N/A** if false, it's a :include: file. 1N/A** ctladdr -- address template to use to fill in these 1N/A** the important things. 1N/A** sendq -- a pointer to the head of the send queue 1N/A** to put these addresses in. 1N/A** aliaslevel -- the alias nesting depth. 1N/A** e -- the current envelope. 1N/A** reads the :include: file and sends to everyone 1N/A** listed in that file. 1N/A** If you have restricted chown (that is, you can't 1N/A** give a file away), it is reasonable to allow programs 1N/A** and files called from this :include: file to be to be 1N/A** run as the owner of the :include: file. This is bogus 1N/A** if there is any chance of someone giving away a file. 1N/A** We assume that pre-POSIX systems can give away files. 1N/A** There is an additional restriction that if you 1N/A** forward to a :include: file, it will not take on 1N/A** the ownership of the :include: file. This may not 1N/A** be necessary, but shouldn't hurt. 1N/A ** If RunAsUser set, won't be able to run programs as user 1N/A ** so mark them as unsafe unless the administrator knows better. 1N/A syserr(
"seteuid(%d) failure (real=%d, eff=%d)",
1N/A#
endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 1N/A syserr(
"setreuid(0, %d) failure (real=%d, eff=%d)",
1N/A#
endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 1N/A#
endif /* MAILER_SETUID_METHOD != USE_SETUID */ 1N/A ** If home directory is remote mounted but server is down, 1N/A ** this can hang or give errors; use a timeout to avoid this 1N/A /* return pseudo-error code */ 1N/A /* check for writable parent directory */ 1N/A /* in safe directory: relax chown & link rules */ 1N/A "%s: unsafe directory path, marked unsafe",
1N/A /* allow links only in unwritable directories */ 1N/A /* don't use this :include: file */ 1N/A syserr(
"!seteuid(0) failure (real=%d, eff=%d)",
1N/A#
else /* USESETEUID */ 1N/A syserr(
"!setreuid(-1, 0) failure (real=%d, eff=%d)",
1N/A syserr(
"!setreuid(%d, 0) failure (real=%d, eff=%d)",
1N/A#
endif /* USESETEUID */ 1N/A syserr(
"!setgid(%d) failure (real=%d eff=%d)",
1N/A#
endif /* HASSETREUID || USESETEUID */ 1N/A /* if path was writable, check to avoid file giveaway tricks */ 1N/A /* if no controlling user or coming from an alias delivery */ 1N/A /* optimization -- avoid getpwuid if we already have info */ 1N/A "%s: user %s has bad shell %s, marked %s",
1N/A /* don't do any more now */ 1N/A ** Check to see if some bad guy can write this file 1N/A ** Group write checking could be more clever, e.g., 1N/A ** guessing as to which groups are actually safe ("sys" 1N/A ** may be; "user" probably is not). 1N/A "%s: %s writable %s file, marked unsafe",
1N/A /* read the file -- each line is a comma-separated list. */ 1N/A /* <sp>#@# introduces a comment anywhere */ 1N/A /* for Japanese character sets */ 1N/A if (p[
1] ==
'@' && p[
2] ==
'#' &&
1N/A "forward %.200s => %s",
1N/A /* just stop reading and processing further entries */ 1N/A /* additional: (?) */ 1N/A syserr(
"Attempt to forward to more than %d addresses (in %s)!",
1N/A ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 1N/A ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 1N/A** SENDTOARGV -- send to an argument vector. 1N/A** argv -- argument vector to send to. 1N/A** e -- the current envelope. 1N/A** puts all addresses on the argument vector onto the 1N/A** GETCTLADDR -- get controlling address from an address header. 1N/A** If none, get one corresponding to the effective userid. 1N/A** a -- the address to find the controller of. 1N/A** the controlling address. 1N/A** SELF_REFERENCE -- check to see if an address references itself 1N/A** The check is done through a chain of aliases. If it is part of 1N/A** a loop, break the loop at the "best" address, that is, the one 1N/A** that exists as a real user. 1N/A** This is to handle the case of: 1N/A** Andrew.Chang: awc@mail.server 1N/A** a -- the address to check. 1N/A** The address that should be retained. 1N/A ADDRESS *c;
/* entry that point to a real mail box */ 1N/A ** Pick the first address that resolved to a real mail box 1N/A ** i.e has a mbdb entry. The returned value will be marked 1N/A ** QSELFREF in recipient(), which in turn will disable alias() 1N/A ** from marking it as QS_IS_DEAD(), which mean it will be used 1N/A ** as a deliverable address. 1N/A ** The 2 key thing to note here are: 1N/A ** 1) we are in a recursive call sequence: 1N/A ** alias->sendtolist->recipient->alias 1N/A ** 2) normally, when we return back to alias(), the address 1N/A ** will be marked QS_EXPANDED, since alias() assumes the 1N/A ** expanded form will be used instead of the current address. 1N/A ** This behaviour is turned off if the address is marked 1N/A ** QSELFREF. We set QSELFREF when we return to recipient(). 1N/A /* ought to cache results here */ 1N/A /* if local delivery, compare usernames */