122710Sdist /*
268839Seric * Copyright (c) 1983, 1995 Eric P. Allman
363589Sbostic * Copyright (c) 1988, 1993
463589Sbostic * The Regents of the University of California. All rights reserved.
533731Sbostic *
642829Sbostic * %sccs.include.redist.c%
733731Sbostic */
822710Sdist
922710Sdist #ifndef lint
10*69952Seric static char sccsid[] = "@(#)recipient.c 8.97 (Berkeley) 06/20/95";
1133731Sbostic #endif /* not lint */
1222710Sdist
1358332Seric # include "sendmail.h"
144174Seric
154174Seric /*
169622Seric ** SENDTOLIST -- Designate a send list.
174174Seric **
184174Seric ** The parameter is a comma-separated list of people to send to.
194174Seric ** This routine arranges to send to all of them.
204174Seric **
214174Seric ** Parameters:
224174Seric ** list -- the send list.
234399Seric ** ctladdr -- the address template for the person to
244399Seric ** send to -- effective uid/gid are important.
255006Seric ** This is typically the alias that caused this
265006Seric ** expansion.
275006Seric ** sendq -- a pointer to the head of a queue to put
285006Seric ** these people into.
2968481Seric ** aliaslevel -- the current alias nesting depth -- to
3068481Seric ** diagnose loops.
3158247Seric ** e -- the envelope in which to add these recipients.
324174Seric **
334174Seric ** Returns:
3458082Seric ** The number of addresses actually on the list.
354174Seric **
364174Seric ** Side Effects:
374174Seric ** none.
384174Seric */
394174Seric
4068481Seric #define MAXRCRSN 10 /* maximum levels of alias recursion */
414174Seric
4268481Seric /* q_flags bits inherited from ctladdr */
4368595Seric #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY)
4468481Seric
4568481Seric int
sendtolist(list,ctladdr,sendq,aliaslevel,e)4668481Seric sendtolist(list, ctladdr, sendq, aliaslevel, e)
474174Seric char *list;
484399Seric ADDRESS *ctladdr;
495198Seric ADDRESS **sendq;
5068481Seric int aliaslevel;
5155012Seric register ENVELOPE *e;
524174Seric {
534174Seric register char *p;
548223Seric register ADDRESS *al; /* list of addresses to send to */
554423Seric bool firstone; /* set on first address sent */
5611446Seric char delimiter; /* the address delimiter */
5758082Seric int naddrs;
5868392Seric int i;
5963847Seric char *oldto = e->e_to;
6068392Seric char *bufp;
6168271Seric char buf[MAXNAME + 1];
624174Seric
6364131Seric if (list == NULL)
6464131Seric {
6564131Seric syserr("sendtolist: null list");
6664131Seric return 0;
6764131Seric }
6864131Seric
697676Seric if (tTd(25, 1))
704444Seric {
714444Seric printf("sendto: %s\n ctladdr=", list);
724444Seric printaddr(ctladdr, FALSE);
734444Seric }
744324Seric
758223Seric /* heuristic to determine old versus new style addresses */
768230Seric if (ctladdr == NULL &&
7756795Seric (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
7856795Seric strchr(list, '<') != NULL || strchr(list, '(') != NULL))
7955012Seric e->e_flags &= ~EF_OLDSTYLE;
8011446Seric delimiter = ' ';
8155012Seric if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL)
8211446Seric delimiter = ',';
838223Seric
844423Seric firstone = TRUE;
854324Seric al = NULL;
8658082Seric naddrs = 0;
878223Seric
8868392Seric /* make sure we have enough space to copy the string */
8968392Seric i = strlen(list) + 1;
9068392Seric if (i <= sizeof buf)
9168271Seric bufp = buf;
9268392Seric else
9368392Seric bufp = xalloc(i);
9468478Seric strcpy(bufp, denlstring(list, FALSE, TRUE));
9568271Seric
9668271Seric for (p = bufp; *p != '\0'; )
9768271Seric {
9858333Seric auto char *delimptr;
998081Seric register ADDRESS *a;
1004319Seric
1018081Seric /* parse the address */
10258050Seric while ((isascii(*p) && isspace(*p)) || *p == ',')
1034174Seric p++;
10464284Seric a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e);
10558333Seric p = delimptr;
1069297Seric if (a == NULL)
1074174Seric continue;
1084324Seric a->q_next = al;
1094399Seric a->q_alias = ctladdr;
1104444Seric
11168481Seric /* arrange to inherit attributes from parent */
11268481Seric if (ctladdr != NULL)
11368481Seric {
11469544Seric ADDRESS *b;
11569544Seric extern ADDRESS *self_reference();
11669544Seric
11768481Seric /* self reference test */
11868481Seric if (sameaddr(ctladdr, a))
11969561Seric {
12069561Seric if (tTd(27, 5))
12169561Seric {
12269561Seric printf("sendtolist: QSELFREF ");
12369561Seric printaddr(ctladdr, FALSE);
12469561Seric }
12568481Seric ctladdr->q_flags |= QSELFREF;
12669561Seric }
12768481Seric
12869544Seric /* check for address loops */
12969544Seric b = self_reference(a, e);
13069544Seric if (b != NULL)
13169544Seric {
13269544Seric b->q_flags |= QSELFREF;
13369561Seric if (tTd(27, 5))
13469561Seric {
13569561Seric printf("sendtolist: QSELFREF ");
13669561Seric printaddr(b, FALSE);
13769561Seric }
13869544Seric if (a != b)
13969544Seric {
14069561Seric if (tTd(27, 5))
14169561Seric {
14269561Seric printf("sendtolist: QDONTSEND ");
14369561Seric printaddr(a, FALSE);
14469561Seric }
14569544Seric a->q_flags |= QDONTSEND;
14669544Seric continue;
14769544Seric }
14869544Seric }
14969544Seric
15068481Seric /* full name */
15168481Seric if (a->q_fullname == NULL)
15268481Seric a->q_fullname = ctladdr->q_fullname;
15368481Seric
15468481Seric /* various flag bits */
15568481Seric a->q_flags &= ~QINHERITEDBITS;
15668481Seric a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
15768481Seric
15868481Seric /* original recipient information */
15968481Seric a->q_orcpt = ctladdr->q_orcpt;
16068481Seric }
16168481Seric
16257731Seric al = a;
1634423Seric firstone = FALSE;
1644324Seric }
1654324Seric
1664324Seric /* arrange to send to everyone on the local send list */
1674324Seric while (al != NULL)
1684324Seric {
1694324Seric register ADDRESS *a = al;
1704324Seric
1714324Seric al = a->q_next;
17268481Seric a = recipient(a, sendq, aliaslevel, e);
17358082Seric naddrs++;
1744174Seric }
1754324Seric
17663847Seric e->e_to = oldto;
17768392Seric if (bufp != buf)
17868392Seric free(bufp);
17958082Seric return (naddrs);
1804174Seric }
1814174Seric /*
1824174Seric ** RECIPIENT -- Designate a message recipient
1834174Seric **
1844174Seric ** Saves the named person for future mailing.
1854174Seric **
1864174Seric ** Parameters:
1874174Seric ** a -- the (preparsed) address header for the recipient.
1885006Seric ** sendq -- a pointer to the head of a queue to put the
1895006Seric ** recipient in. Duplicate supression is done
1905006Seric ** in this queue.
19168481Seric ** aliaslevel -- the current alias nesting depth.
19257731Seric ** e -- the current envelope.
1934174Seric **
1944174Seric ** Returns:
19512613Seric ** The actual address in the queue. This will be "a" if
19612613Seric ** the address is not a duplicate, else the original address.
1974174Seric **
1984174Seric ** Side Effects:
1994174Seric ** none.
2004174Seric */
2014174Seric
20212613Seric ADDRESS *
recipient(a,sendq,aliaslevel,e)20368481Seric recipient(a, sendq, aliaslevel, e)
2044174Seric register ADDRESS *a;
2055006Seric register ADDRESS **sendq;
20668481Seric int aliaslevel;
20755012Seric register ENVELOPE *e;
2084174Seric {
2094174Seric register ADDRESS *q;
2104319Seric ADDRESS **pq;
2114174Seric register struct mailer *m;
2129210Seric register char *p;
2139210Seric bool quoted = FALSE; /* set if the addr has a quote bit */
21453735Seric int findusercount = 0;
21568603Seric bool initialdontsend = bitset(QDONTSEND, a->q_flags);
21668481Seric int i;
21768481Seric char *buf;
21868528Seric char buf0[MAXNAME + 1]; /* unquoted image of the user name */
21958247Seric extern int safefile();
2204174Seric
22155012Seric e->e_to = a->q_paddr;
2224600Seric m = a->q_mailer;
2234174Seric errno = 0;
22468603Seric if (aliaslevel == 0)
22568603Seric a->q_flags |= QPRIMARY;
2267676Seric if (tTd(26, 1))
2274444Seric {
22868603Seric printf("\nrecipient (%d): ", aliaslevel);
2294444Seric printaddr(a, FALSE);
2304444Seric }
2314174Seric
23264146Seric /* if this is primary, add it to the original recipient list */
23364146Seric if (a->q_alias == NULL)
23464146Seric {
23564146Seric if (e->e_origrcpt == NULL)
23664146Seric e->e_origrcpt = a->q_paddr;
23764146Seric else if (e->e_origrcpt != a->q_paddr)
23864146Seric e->e_origrcpt = "";
23964146Seric }
24064146Seric
2414174Seric /* break aliasing loops */
24268481Seric if (aliaslevel > MAXRCRSN)
2434174Seric {
24468857Seric a->q_status = "5.4.6";
24568481Seric usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max",
24668481Seric aliaslevel, MAXRCRSN);
24712613Seric return (a);
2484174Seric }
2494174Seric
2504174Seric /*
2514627Seric ** Finish setting up address structure.
2524174Seric */
2534174Seric
25416160Seric /* get unquoted user for file, program or user.name check */
25568481Seric i = strlen(a->q_user);
25668528Seric if (i >= sizeof buf0)
25768481Seric buf = xalloc(i + 1);
25868481Seric else
25968481Seric buf = buf0;
2609210Seric (void) strcpy(buf, a->q_user);
2619210Seric for (p = buf; *p != '\0' && !quoted; p++)
2629210Seric {
26354993Seric if (*p == '\\')
2649210Seric quoted = TRUE;
2659210Seric }
26654983Seric stripquotes(buf);
2679210Seric
26857402Seric /* check for direct mailing to restricted mailers */
26965496Seric if (m == ProgMailer)
2704174Seric {
27165496Seric if (a->q_alias == NULL)
27265496Seric {
27365496Seric a->q_flags |= QBADADDR;
27468857Seric a->q_status = "5.7.1";
27565496Seric usrerr("550 Cannot mail directly to programs");
27665496Seric }
27765496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
27865496Seric {
27965496Seric a->q_flags |= QBADADDR;
28068857Seric a->q_status = "5.7.1";
28165496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs",
28265496Seric a->q_alias->q_ruser, MyHostName);
28365496Seric }
28465496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
28565496Seric {
28665496Seric a->q_flags |= QBADADDR;
28768857Seric a->q_status = "5.7.1";
28865496Seric usrerr("550 Address %s is unsafe for mailing to programs",
28965496Seric a->q_alias->q_paddr);
29065496Seric }
2914174Seric }
2924174Seric
2934174Seric /*
2944419Seric ** Look up this person in the recipient list.
2954419Seric ** If they are there already, return, otherwise continue.
2964419Seric ** If the list is empty, just add it. Notice the cute
2974419Seric ** hack to make from addresses suppress things correctly:
2984419Seric ** the QDONTSEND bit will be set in the send list.
2994419Seric ** [Please note: the emphasis is on "hack."]
3004174Seric */
3014174Seric
3025006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
3034174Seric {
30458294Seric if (sameaddr(q, a))
3054174Seric {
3067676Seric if (tTd(26, 1))
3074444Seric {
3084444Seric printf("%s in sendq: ", a->q_paddr);
3094444Seric printaddr(q, FALSE);
3104444Seric }
31165593Seric if (!bitset(QPRIMARY, q->q_flags))
31258065Seric {
31365593Seric if (!bitset(QDONTSEND, a->q_flags))
31458151Seric message("duplicate suppressed");
31565593Seric q->q_flags |= a->q_flags;
31665593Seric }
31765593Seric else if (bitset(QSELFREF, q->q_flags))
31865579Seric q->q_flags |= a->q_flags & ~QDONTSEND;
31963847Seric a = q;
32068481Seric goto done;
3214174Seric }
3224319Seric }
3234174Seric
3244319Seric /* add address on list */
32558884Seric *pq = a;
32658884Seric a->q_next = NULL;
3274174Seric
3284174Seric /*
32957402Seric ** Alias the name and handle special mailer types.
3304174Seric */
3314174Seric
33253735Seric trylocaluser:
33355354Seric if (tTd(29, 7))
33455354Seric printf("at trylocaluser %s\n", a->q_user);
33555354Seric
33658680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
33763847Seric goto testselfdestruct;
33857402Seric
33957402Seric if (m == InclMailer)
3404174Seric {
34157402Seric a->q_flags |= QDONTSEND;
34264761Seric if (a->q_alias == NULL)
3434174Seric {
34458680Seric a->q_flags |= QBADADDR;
34568857Seric a->q_status = "5.7.1";
34658151Seric usrerr("550 Cannot mail directly to :include:s");
3474174Seric }
3484174Seric else
34950556Seric {
35059563Seric int ret;
35158247Seric
35258151Seric message("including file %s", a->q_user);
35368481Seric ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e);
35459563Seric if (transienterror(ret))
35559563Seric {
35659563Seric #ifdef LOG
35759563Seric if (LogLevel > 2)
35866239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s",
35966284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id,
36066284Seric a->q_user, errstring(ret));
36159563Seric #endif
36263853Seric a->q_flags |= QQUEUEUP;
36365215Seric a->q_flags &= ~QDONTSEND;
36459563Seric usrerr("451 Cannot open %s: %s",
36559563Seric a->q_user, errstring(ret));
36659563Seric }
36759563Seric else if (ret != 0)
36859563Seric {
36963938Seric a->q_flags |= QBADADDR;
37068857Seric a->q_status = "5.2.4";
37159563Seric usrerr("550 Cannot open %s: %s",
37259563Seric a->q_user, errstring(ret));
37359563Seric }
37450556Seric }
3754174Seric }
37657642Seric else if (m == FileMailer)
3774174Seric {
3784329Seric extern bool writable();
3794174Seric
38051317Seric /* check if writable or creatable */
38164761Seric if (a->q_alias == NULL)
3824174Seric {
38358680Seric a->q_flags |= QBADADDR;
38468857Seric a->q_status = "5.7.1";
38558151Seric usrerr("550 Cannot mail directly to files");
3864174Seric }
38765496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
38865496Seric {
38965496Seric a->q_flags |= QBADADDR;
39068857Seric a->q_status = "5.7.1";
39165496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to files",
39265496Seric a->q_alias->q_ruser, MyHostName);
39365496Seric }
39465496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
39565496Seric {
39665496Seric a->q_flags |= QBADADDR;
39768857Seric a->q_status = "5.7.1";
39865496Seric usrerr("550 Address %s is unsafe for mailing to files",
39965496Seric a->q_alias->q_paddr);
40065496Seric }
40168494Seric else if (!writable(buf, getctladdr(a), SFF_CREAT))
40251317Seric {
40358680Seric a->q_flags |= QBADADDR;
40468481Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias,
40568481Seric (time_t) 0, e);
40651317Seric }
40751317Seric }
40851317Seric
40957402Seric /* try aliasing */
41069904Seric if (!quoted && !bitset(QDONTSEND, a->q_flags) &&
41169904Seric bitnset(M_ALIASABLE, m->m_flags))
41268481Seric alias(a, sendq, aliaslevel, e);
41357402Seric
41469714Seric # if USERDB
41557402Seric /* if not aliased, look it up in the user database */
41668481Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) &&
41768481Seric bitnset(M_CHECKUDB, m->m_flags))
41857402Seric {
41957402Seric extern int udbexpand();
42057402Seric
42168481Seric if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL)
42257402Seric {
42363853Seric a->q_flags |= QQUEUEUP;
42457402Seric if (e->e_message == NULL)
42557402Seric e->e_message = newstr("Deferred: user database error");
42657402Seric # ifdef LOG
42758020Seric if (LogLevel > 8)
42859623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s",
42966284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id,
43066284Seric errstring(errno));
43157402Seric # endif
43259615Seric message("queued (user database error): %s",
43359615Seric errstring(errno));
43457642Seric e->e_nrcpts++;
43563847Seric goto testselfdestruct;
43657402Seric }
43757402Seric }
43857402Seric # endif
43957402Seric
44051317Seric /*
44151317Seric ** If we have a level two config file, then pass the name through
44251317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right
44351317Seric ** to send rewrite it to another mailer. This gives us a hook
44451317Seric ** after local aliasing has been done.
44551317Seric */
44651317Seric
44751317Seric if (tTd(29, 5))
44851317Seric {
44951317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t",
45051317Seric ConfigLevel, RewriteRules[5]);
45151317Seric printaddr(a, FALSE);
45251317Seric }
45368481Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
45468481Seric ConfigLevel >= 2 && RewriteRules[5] != NULL &&
45568481Seric bitnset(M_TRYRULESET5, m->m_flags))
45651317Seric {
45768603Seric maplocaluser(a, sendq, aliaslevel + 1, e);
45851317Seric }
45951317Seric
46051317Seric /*
46151317Seric ** If it didn't get rewritten to another mailer, go ahead
46251317Seric ** and deliver it.
46351317Seric */
46451317Seric
46568481Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
46668481Seric bitnset(M_HASPWENT, m->m_flags))
46751317Seric {
46855354Seric auto bool fuzzy;
46951317Seric register struct passwd *pw;
47051317Seric extern struct passwd *finduser();
47151317Seric
47251317Seric /* warning -- finduser may trash buf */
47355354Seric pw = finduser(buf, &fuzzy);
47451317Seric if (pw == NULL)
47551317Seric {
47658680Seric a->q_flags |= QBADADDR;
47768857Seric a->q_status = "5.1.1";
47868481Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias,
47968481Seric (time_t) 0, e);
48051317Seric }
4814174Seric else
4824174Seric {
48368528Seric char nbuf[MAXNAME + 1];
4844373Seric
48555354Seric if (fuzzy)
4864174Seric {
48753735Seric /* name was a fuzzy match */
48851317Seric a->q_user = newstr(pw->pw_name);
48953735Seric if (findusercount++ > 3)
49053735Seric {
49158680Seric a->q_flags |= QBADADDR;
49268857Seric a->q_status = "5.4.6";
49358151Seric usrerr("554 aliasing/forwarding loop for %s broken",
49453735Seric pw->pw_name);
49568481Seric goto done;
49653735Seric }
49753735Seric
49853735Seric /* see if it aliases */
49951317Seric (void) strcpy(buf, pw->pw_name);
50053735Seric goto trylocaluser;
5014174Seric }
50265822Seric if (strcmp(pw->pw_dir, "/") == 0)
50365822Seric a->q_home = "";
50465822Seric else
50565822Seric a->q_home = newstr(pw->pw_dir);
50651317Seric a->q_uid = pw->pw_uid;
50751317Seric a->q_gid = pw->pw_gid;
50859083Seric a->q_ruser = newstr(pw->pw_name);
50951317Seric a->q_flags |= QGOODUID;
51051317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf);
51151317Seric if (nbuf[0] != '\0')
51251317Seric a->q_fullname = newstr(nbuf);
51369894Seric if (!usershellok(pw->pw_name, pw->pw_shell))
51465206Seric {
51565211Seric a->q_flags |= QBOGUSSHELL;
51665206Seric }
51769619Seric if (bitset(EF_VRFYONLY, e->e_flags))
51869619Seric {
51969619Seric /* don't do any more now */
52069619Seric a->q_flags |= QVERIFIED;
52169619Seric }
52269619Seric else if (!quoted)
52368481Seric forward(a, sendq, aliaslevel, e);
5244174Seric }
5254174Seric }
52657642Seric if (!bitset(QDONTSEND, a->q_flags))
52757642Seric e->e_nrcpts++;
52863847Seric
52963847Seric testselfdestruct:
53068603Seric a->q_flags |= QTHISPASS;
53163978Seric if (tTd(26, 8))
53263847Seric {
53363978Seric printf("testselfdestruct: ");
53468603Seric printaddr(a, FALSE);
53568603Seric if (tTd(26, 10))
53668603Seric {
53768603Seric printf("SENDQ:\n");
53868603Seric printaddr(*sendq, TRUE);
53968603Seric printf("----\n");
54068603Seric }
54163978Seric }
54263978Seric if (a->q_alias == NULL && a != &e->e_from &&
54363978Seric bitset(QDONTSEND, a->q_flags))
54463978Seric {
54568603Seric for (q = *sendq; q != NULL; q = q->q_next)
54668603Seric {
54769898Seric if (!bitset(QDONTSEND, q->q_flags) &&
54868603Seric bitset(QTHISPASS, q->q_flags))
54968603Seric break;
55068603Seric }
55163978Seric if (q == NULL)
55263847Seric {
55363847Seric a->q_flags |= QBADADDR;
55468858Seric a->q_status = "5.4.6";
55563847Seric usrerr("554 aliasing/forwarding loop broken");
55663847Seric }
55763847Seric }
55868481Seric
55968481Seric done:
56068603Seric a->q_flags |= QTHISPASS;
56168481Seric if (buf != buf0)
56268481Seric free(buf);
56368603Seric
56468603Seric /*
56568603Seric ** If we are at the top level, check to see if this has
56668603Seric ** expanded to exactly one address. If so, it can inherit
56768603Seric ** the primaryness of the address.
56868603Seric **
56968603Seric ** While we're at it, clear the QTHISPASS bits.
57068603Seric */
57168603Seric
57268603Seric if (aliaslevel == 0)
57368603Seric {
57468603Seric int nrcpts = 0;
57568603Seric ADDRESS *only;
57668603Seric
57768603Seric for (q = *sendq; q != NULL; q = q->q_next)
57868603Seric {
57968603Seric if (bitset(QTHISPASS, q->q_flags) &&
58068603Seric !bitset(QDONTSEND|QBADADDR, q->q_flags))
58168603Seric {
58268603Seric nrcpts++;
58368603Seric only = q;
58468603Seric }
58568603Seric q->q_flags &= ~QTHISPASS;
58668603Seric }
58768603Seric if (nrcpts == 1)
58868603Seric {
58968867Seric /* check to see if this actually got a new owner */
59068867Seric q = only;
59168867Seric while ((q = q->q_alias) != NULL)
59268867Seric {
59368867Seric if (q->q_owner != NULL)
59468867Seric break;
59568867Seric }
59668867Seric if (q == NULL)
59768867Seric only->q_flags |= QPRIMARY;
59868867Seric }
59968867Seric else if (!initialdontsend && nrcpts > 0)
60068867Seric {
60168603Seric /* arrange for return receipt */
60268603Seric e->e_flags |= EF_SENDRECEIPT;
60368867Seric a->q_flags |= QEXPANDED;
60468603Seric if (e->e_xfp != NULL)
60568603Seric fprintf(e->e_xfp,
60668603Seric "%s... expanded to multiple addresses\n",
60768603Seric a->q_paddr);
60868603Seric }
60968603Seric }
61068603Seric
61112613Seric return (a);
6124174Seric }
6134174Seric /*
6144373Seric ** FINDUSER -- find the password entry for a user.
6154373Seric **
6164373Seric ** This looks a lot like getpwnam, except that it may want to
6174373Seric ** do some fancier pattern matching in /etc/passwd.
6184373Seric **
6199379Seric ** This routine contains most of the time of many sendmail runs.
6209379Seric ** It deserves to be optimized.
6219379Seric **
6224373Seric ** Parameters:
6234373Seric ** name -- the name to match against.
62455354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry
62555354Seric ** was found using the fuzzy matching algorithm;
62655354Seric ** set to FALSE otherwise.
6274373Seric **
6284373Seric ** Returns:
6294373Seric ** A pointer to a pw struct.
6304373Seric ** NULL if name is unknown or ambiguous.
6314373Seric **
6324373Seric ** Side Effects:
6334407Seric ** may modify name.
6344373Seric */
6354373Seric
6364373Seric struct passwd *
finduser(name,fuzzyp)63755354Seric finduser(name, fuzzyp)
6384373Seric char *name;
63955354Seric bool *fuzzyp;
6404373Seric {
6414376Seric register struct passwd *pw;
6424407Seric register char *p;
6434373Seric
64455354Seric if (tTd(29, 4))
64555354Seric printf("finduser(%s): ", name);
64655354Seric
64755354Seric *fuzzyp = FALSE;
6484407Seric
64968481Seric #ifdef HESIOD
65064673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
65164673Seric for (p = name; *p != '\0'; p++)
65264673Seric if (!isascii(*p) || !isdigit(*p))
65364673Seric break;
65464673Seric if (*p == '\0')
65564673Seric {
65664673Seric if (tTd(29, 4))
65764673Seric printf("failed (numeric input)\n");
65864673Seric return NULL;
65964673Seric }
66068481Seric #endif
66164673Seric
66225777Seric /* look up this login name using fast path */
66368693Seric if ((pw = sm_getpwnam(name)) != NULL)
66455354Seric {
66555354Seric if (tTd(29, 4))
66655354Seric printf("found (non-fuzzy)\n");
66712634Seric return (pw);
66855354Seric }
66912634Seric
67069881Seric #if MATCHGECOS
67153735Seric /* see if fuzzy matching allowed */
67253735Seric if (!MatchGecos)
67355354Seric {
67455354Seric if (tTd(29, 4))
67555354Seric printf("not found (fuzzy disabled)\n");
67653735Seric return NULL;
67755354Seric }
67853735Seric
67912634Seric /* search for a matching full name instead */
68025777Seric for (p = name; *p != '\0'; p++)
68125777Seric {
68225777Seric if (*p == (SpaceSub & 0177) || *p == '_')
68325777Seric *p = ' ';
68425777Seric }
68523107Seric (void) setpwent();
6864376Seric while ((pw = getpwent()) != NULL)
6874376Seric {
68868528Seric char buf[MAXNAME + 1];
6894376Seric
6904998Seric buildfname(pw->pw_gecos, pw->pw_name, buf);
69156795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name))
6924381Seric {
69355354Seric if (tTd(29, 4))
69455354Seric printf("fuzzy matches %s\n", pw->pw_name);
69558151Seric message("sending to login name %s", pw->pw_name);
69655354Seric *fuzzyp = TRUE;
6974376Seric return (pw);
6984377Seric }
6994376Seric }
70055354Seric if (tTd(29, 4))
70155354Seric printf("no fuzzy match found\n");
70259015Seric #else
70359015Seric if (tTd(29, 4))
70459015Seric printf("not found (fuzzy disabled)\n");
70559015Seric #endif
7064376Seric return (NULL);
7074373Seric }
7084373Seric /*
7094329Seric ** WRITABLE -- predicate returning if the file is writable.
7104329Seric **
7114329Seric ** This routine must duplicate the algorithm in sys/fio.c.
7124329Seric ** Unfortunately, we cannot use the access call since we
7134329Seric ** won't necessarily be the real uid when we try to
7144329Seric ** actually open the file.
7154329Seric **
7164329Seric ** Notice that ANY file with ANY execute bit is automatically
7174329Seric ** not writable. This is also enforced by mailfile.
7184329Seric **
7194329Seric ** Parameters:
72065064Seric ** filename -- the file name to check.
72165112Seric ** ctladdr -- the controlling address for this file.
72265064Seric ** flags -- SFF_* flags to control the function.
7234329Seric **
7244329Seric ** Returns:
7254329Seric ** TRUE -- if we will be able to write this file.
7264329Seric ** FALSE -- if we cannot write this file.
7274329Seric **
7284329Seric ** Side Effects:
7294329Seric ** none.
7304329Seric */
7314329Seric
7324329Seric bool
writable(filename,ctladdr,flags)73365112Seric writable(filename, ctladdr, flags)
73464819Seric char *filename;
73565112Seric ADDRESS *ctladdr;
73665064Seric int flags;
7374329Seric {
73855372Seric uid_t euid;
73955372Seric gid_t egid;
74064944Seric char *uname;
7414329Seric
74264819Seric if (tTd(29, 5))
74368802Seric printf("writable(%s, 0x%x)\n", filename, flags);
74464944Seric
74564944Seric /*
74664944Seric ** File does exist -- check that it is writable.
74764944Seric */
74864944Seric
74965112Seric if (ctladdr != NULL && geteuid() == 0)
75064944Seric {
75165112Seric euid = ctladdr->q_uid;
75265112Seric egid = ctladdr->q_gid;
75365112Seric uname = ctladdr->q_user;
75464944Seric }
75568802Seric else if (bitset(SFF_RUNASREALUID, flags))
75665112Seric {
75765112Seric euid = RealUid;
75865112Seric egid = RealGid;
75965112Seric uname = RealUserName;
76065112Seric }
761*69952Seric else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags))
76268481Seric {
76368481Seric euid = FileMailer->m_uid;
76468481Seric egid = FileMailer->m_gid;
76569748Seric uname = NULL;
76668481Seric }
76768481Seric else
76868481Seric {
76968481Seric euid = egid = 0;
77069748Seric uname = NULL;
77168481Seric }
772*69952Seric if (!bitset(SFF_ROOTOK, flags))
77365138Seric {
774*69952Seric if (euid == 0)
775*69952Seric {
776*69952Seric euid = DefUid;
777*69952Seric uname = DefUser;
778*69952Seric }
779*69952Seric if (egid == 0)
780*69952Seric egid = DefGid;
78165138Seric }
7824329Seric if (geteuid() == 0)
78368494Seric flags |= SFF_SETUIDOK;
7844329Seric
78568494Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL);
78665067Seric return errno == 0;
7874329Seric }
7884329Seric /*
7894174Seric ** INCLUDE -- handle :include: specification.
7904174Seric **
7914174Seric ** Parameters:
7924174Seric ** fname -- filename to include.
79353037Seric ** forwarding -- if TRUE, we are reading a .forward file.
79453037Seric ** if FALSE, it's a :include: file.
7954399Seric ** ctladdr -- address template to use to fill in these
7964399Seric ** addresses -- effective user/group id are
7974399Seric ** the important things.
7985006Seric ** sendq -- a pointer to the head of the send queue
7995006Seric ** to put these addresses in.
80068481Seric ** aliaslevel -- the alias nesting depth.
80168481Seric ** e -- the current envelope.
8024174Seric **
8034174Seric ** Returns:
80457136Seric ** open error status
8054174Seric **
8064174Seric ** Side Effects:
8074174Seric ** reads the :include: file and sends to everyone
8084174Seric ** listed in that file.
80965909Seric **
81065909Seric ** Security Note:
81165909Seric ** If you have restricted chown (that is, you can't
81265909Seric ** give a file away), it is reasonable to allow programs
81365909Seric ** and files called from this :include: file to be to be
81465909Seric ** run as the owner of the :include: file. This is bogus
81565909Seric ** if there is any chance of someone giving away a file.
81665909Seric ** We assume that pre-POSIX systems can give away files.
81765909Seric **
81865909Seric ** There is an additional restriction that if you
81965909Seric ** forward to a :include: file, it will not take on
82065909Seric ** the ownership of the :include: file. This may not
82165909Seric ** be necessary, but shouldn't hurt.
8224174Seric */
8234174Seric
82453037Seric static jmp_buf CtxIncludeTimeout;
82568481Seric static void includetimeout();
82653037Seric
82757136Seric int
include(fname,forwarding,ctladdr,sendq,aliaslevel,e)82868481Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
8294174Seric char *fname;
83053037Seric bool forwarding;
8314399Seric ADDRESS *ctladdr;
8325006Seric ADDRESS **sendq;
83368481Seric int aliaslevel;
83455012Seric ENVELOPE *e;
8354174Seric {
83668481Seric FILE *fp = NULL;
83755012Seric char *oldto = e->e_to;
8389379Seric char *oldfilename = FileName;
8399379Seric int oldlinenumber = LineNumber;
84053037Seric register EVENT *ev = NULL;
84158082Seric int nincludes;
84264325Seric register ADDRESS *ca;
84364325Seric uid_t saveduid, uid;
84464325Seric gid_t savedgid, gid;
84564083Seric char *uname;
84664325Seric int rval = 0;
84768513Seric int sfflags = SFF_REGONLY;
84865496Seric struct stat st;
84965948Seric char buf[MAXLINE];
85065909Seric #ifdef _POSIX_CHOWN_RESTRICTED
85165948Seric # if _POSIX_CHOWN_RESTRICTED == -1
85265948Seric # define safechown FALSE
85365948Seric # else
85465948Seric # define safechown TRUE
85565948Seric # endif
85665948Seric #else
85765948Seric # ifdef _PC_CHOWN_RESTRICTED
85865909Seric bool safechown;
85965948Seric # else
86065948Seric # ifdef BSD
86165948Seric # define safechown TRUE
86265948Seric # else
86365948Seric # define safechown FALSE
86465948Seric # endif
86565948Seric # endif
86665909Seric #endif
86765948Seric extern bool chownsafe();
8684174Seric
86957186Seric if (tTd(27, 2))
87057186Seric printf("include(%s)\n", fname);
87163902Seric if (tTd(27, 4))
87263902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid());
87363581Seric if (tTd(27, 14))
87463581Seric {
87563581Seric printf("ctladdr ");
87663581Seric printaddr(ctladdr, FALSE);
87763581Seric }
87857186Seric
87964325Seric if (tTd(27, 9))
88064325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid());
88153037Seric
88268513Seric if (forwarding)
88369306Seric sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOSLINK;
88468513Seric
88563581Seric ca = getctladdr(ctladdr);
88663581Seric if (ca == NULL)
88764083Seric {
88864846Seric uid = DefUid;
88964846Seric gid = DefGid;
89064846Seric uname = DefUser;
89164083Seric }
89263581Seric else
89364083Seric {
89463581Seric uid = ca->q_uid;
89564083Seric gid = ca->q_gid;
89664083Seric uname = ca->q_user;
89768481Seric }
89869638Seric #if HASSETREUID || USESETEUID
89968481Seric saveduid = geteuid();
90068481Seric savedgid = getegid();
90168481Seric if (saveduid == 0)
90268481Seric {
90368481Seric initgroups(uname, gid);
90468481Seric if (uid != 0)
90564325Seric {
90669638Seric # if USESETEUID
90769638Seric if (seteuid(uid) < 0)
90869638Seric syserr("seteuid(%d) failure (real=%d, eff=%d)",
90969638Seric uid, getuid(), geteuid());
91069638Seric # else
91168481Seric if (setreuid(0, uid) < 0)
91268481Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)",
91368481Seric uid, getuid(), geteuid());
91469638Seric # endif
91568481Seric else
91668481Seric sfflags |= SFF_NOPATHCHECK;
91764325Seric }
91868481Seric }
91969544Seric #endif
92063581Seric
92164325Seric if (tTd(27, 9))
92264325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid());
92364325Seric
92464325Seric /*
92564325Seric ** If home directory is remote mounted but server is down,
92664325Seric ** this can hang or give errors; use a timeout to avoid this
92764325Seric */
92864325Seric
92953037Seric if (setjmp(CtxIncludeTimeout) != 0)
93053037Seric {
93163853Seric ctladdr->q_flags |= QQUEUEUP;
93253037Seric errno = 0;
93363993Seric
93463993Seric /* return pseudo-error code */
93564325Seric rval = EOPENTIMEOUT;
93664325Seric goto resetuid;
93753037Seric }
93868481Seric if (TimeOuts.to_fileopen > 0)
93968481Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0);
94068481Seric else
94168481Seric ev = NULL;
94253037Seric
94363581Seric /* the input file must be marked safe */
94468494Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL);
94564329Seric if (rval != 0)
94653037Seric {
94764325Seric /* don't use this :include: file */
94857186Seric if (tTd(27, 4))
94958247Seric printf("include: not safe (uid=%d): %s\n",
95064329Seric uid, errstring(rval));
95153037Seric }
95265496Seric else
9534174Seric {
95465496Seric fp = fopen(fname, "r");
95565496Seric if (fp == NULL)
95658061Seric {
95764329Seric rval = errno;
95865496Seric if (tTd(27, 4))
95965496Seric printf("include: open: %s\n", errstring(rval));
96058061Seric }
9614406Seric }
96268481Seric if (ev != NULL)
96368481Seric clrevent(ev);
96453037Seric
96564570Seric resetuid:
96664570Seric
96769638Seric #if HASSETREUID || USESETEUID
96864570Seric if (saveduid == 0)
96964570Seric {
97064570Seric if (uid != 0)
97168481Seric {
97269638Seric # if USESETEUID
97369638Seric if (seteuid(0) < 0)
97469638Seric syserr("seteuid(0) failure (real=%d, eff=%d)",
97569638Seric getuid(), geteuid());
97669638Seric # else
97768481Seric if (setreuid(-1, 0) < 0)
97868481Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)",
97968481Seric getuid(), geteuid());
98068481Seric if (setreuid(RealUid, 0) < 0)
98164570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
98264570Seric RealUid, getuid(), geteuid());
98369638Seric # endif
98468481Seric }
98564570Seric setgid(savedgid);
98664570Seric }
98764570Seric #endif
98864570Seric
98964570Seric if (tTd(27, 9))
99064570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid());
99164570Seric
99265593Seric if (rval == EOPENTIMEOUT)
99365593Seric usrerr("451 open timeout on %s", fname);
99465593Seric
99564570Seric if (fp == NULL)
99664570Seric return rval;
99764570Seric
99865496Seric if (fstat(fileno(fp), &st) < 0)
99965496Seric {
100065496Seric rval = errno;
100165496Seric syserr("Cannot fstat %s!", fname);
100265496Seric return rval;
100365496Seric }
100465496Seric
100565948Seric #ifndef safechown
100665948Seric safechown = chownsafe(fileno(fp));
100765948Seric #endif
100865909Seric if (ca == NULL && safechown)
100965496Seric {
101065496Seric ctladdr->q_uid = st.st_uid;
101165496Seric ctladdr->q_gid = st.st_gid;
101265496Seric ctladdr->q_flags |= QGOODUID;
101365496Seric }
101465496Seric if (ca != NULL && ca->q_uid == st.st_uid)
101565496Seric {
101665496Seric /* optimization -- avoid getpwuid if we already have info */
101765496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
101865496Seric ctladdr->q_ruser = ca->q_ruser;
101965496Seric }
102065496Seric else
102165496Seric {
102265496Seric register struct passwd *pw;
102365496Seric
102468693Seric pw = sm_getpwuid(st.st_uid);
102568481Seric if (pw == NULL)
102668481Seric ctladdr->q_flags |= QBOGUSSHELL;
102768481Seric else
102868478Seric {
102968481Seric char *sh;
103068481Seric
103168478Seric ctladdr->q_ruser = newstr(pw->pw_name);
103268478Seric if (safechown)
103368478Seric sh = pw->pw_shell;
103465909Seric else
103568481Seric sh = "/SENDMAIL/ANY/SHELL/";
103669894Seric if (!usershellok(pw->pw_name, sh))
103768481Seric {
103868481Seric if (safechown)
103968481Seric ctladdr->q_flags |= QBOGUSSHELL;
104068481Seric else
104168481Seric ctladdr->q_flags |= QUNSAFEADDR;
104268481Seric }
104365496Seric }
104465496Seric }
104565496Seric
104658092Seric if (bitset(EF_VRFYONLY, e->e_flags))
104758092Seric {
104858092Seric /* don't do any more now */
104958868Seric ctladdr->q_flags |= QVERIFIED;
105058884Seric e->e_nrcpts++;
105158680Seric xfclose(fp, "include", fname);
105264570Seric return rval;
105358092Seric }
105458092Seric
105565496Seric /*
105665496Seric ** Check to see if some bad guy can write this file
105765496Seric **
105865496Seric ** This should really do something clever with group
105965496Seric ** permissions; currently we just view world writable
106065496Seric ** as unsafe. Also, we don't check for writable
106165496Seric ** directories in the path. We've got to leave
106265496Seric ** something for the local sysad to do.
106365496Seric */
106465496Seric
106565496Seric if (bitset(S_IWOTH, st.st_mode))
106665496Seric ctladdr->q_flags |= QUNSAFEADDR;
106765496Seric
10684174Seric /* read the file -- each line is a comma-separated list. */
10699379Seric FileName = fname;
10709379Seric LineNumber = 0;
107158082Seric ctladdr->q_flags &= ~QSELFREF;
107258082Seric nincludes = 0;
10734174Seric while (fgets(buf, sizeof buf, fp) != NULL)
10744174Seric {
107556795Seric register char *p = strchr(buf, '\n');
10764174Seric
107740963Sbostic LineNumber++;
10784174Seric if (p != NULL)
10794174Seric *p = '\0';
108057186Seric if (buf[0] == '#' || buf[0] == '\0')
108157139Seric continue;
108268787Seric
108368787Seric /* <sp>#@# introduces a comment anywhere */
108468787Seric /* for Japanese character sets */
108568787Seric for (p = buf; (p = strchr(++p, '#')) != NULL; )
108668787Seric {
108768787Seric if (p[1] == '@' && p[2] == '#' &&
108868787Seric isascii(p[-1]) && isspace(p[-1]) &&
108969714Seric (p[3] == '\0' || (isascii(p[3]) && isspace(p[3]))))
109068787Seric {
109168787Seric p[-1] = '\0';
109268787Seric break;
109368787Seric }
109468787Seric }
109568787Seric if (buf[0] == '\0')
109668787Seric continue;
109768787Seric
109858008Seric e->e_to = NULL;
109958151Seric message("%s to %s",
110053037Seric forwarding ? "forwarding" : "sending", buf);
110157977Seric #ifdef LOG
110258020Seric if (forwarding && LogLevel > 9)
110357977Seric syslog(LOG_INFO, "%s: forward %s => %s",
110466284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id,
110566284Seric oldto, buf);
110657977Seric #endif
110757977Seric
110868481Seric nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e);
11094174Seric }
111063902Seric
111163902Seric if (ferror(fp) && tTd(27, 3))
111263902Seric printf("include: read error: %s\n", errstring(errno));
111358082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
111458065Seric {
111558065Seric if (tTd(27, 5))
111658065Seric {
111758065Seric printf("include: QDONTSEND ");
111858065Seric printaddr(ctladdr, FALSE);
111958065Seric }
112058065Seric ctladdr->q_flags |= QDONTSEND;
112158065Seric }
11224174Seric
112358680Seric (void) xfclose(fp, "include", fname);
11249379Seric FileName = oldfilename;
11259379Seric LineNumber = oldlinenumber;
112663847Seric e->e_to = oldto;
112764325Seric return rval;
11284174Seric }
112953037Seric
113068481Seric static void
includetimeout()113153037Seric includetimeout()
113253037Seric {
113353037Seric longjmp(CtxIncludeTimeout, 1);
113453037Seric }
11354324Seric /*
11364324Seric ** SENDTOARGV -- send to an argument vector.
11374324Seric **
11384324Seric ** Parameters:
11394324Seric ** argv -- argument vector to send to.
114058247Seric ** e -- the current envelope.
11414324Seric **
11424324Seric ** Returns:
11434324Seric ** none.
11444324Seric **
11454324Seric ** Side Effects:
11464324Seric ** puts all addresses on the argument vector onto the
11474324Seric ** send queue.
11484324Seric */
11494324Seric
115069748Seric void
sendtoargv(argv,e)115155012Seric sendtoargv(argv, e)
11524324Seric register char **argv;
115355012Seric register ENVELOPE *e;
11544324Seric {
11554324Seric register char *p;
11564324Seric
11574324Seric while ((p = *argv++) != NULL)
11584324Seric {
115968481Seric (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
11604324Seric }
11614324Seric }
11624399Seric /*
11634399Seric ** GETCTLADDR -- get controlling address from an address header.
11644399Seric **
11654399Seric ** If none, get one corresponding to the effective userid.
11664399Seric **
11674399Seric ** Parameters:
11684399Seric ** a -- the address to find the controller of.
11694399Seric **
11704399Seric ** Returns:
11714399Seric ** the controlling address.
11724399Seric **
11734399Seric ** Side Effects:
11744399Seric ** none.
11754399Seric */
11764399Seric
11774399Seric ADDRESS *
getctladdr(a)11784399Seric getctladdr(a)
11794399Seric register ADDRESS *a;
11804399Seric {
11814404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags))
11824399Seric a = a->q_alias;
11834399Seric return (a);
11844399Seric }
118569544Seric /*
118669544Seric ** SELF_REFERENCE -- check to see if an address references itself
118769544Seric **
118869544Seric ** The check is done through a chain of aliases. If it is part of
118969544Seric ** a loop, break the loop at the "best" address, that is, the one
119069544Seric ** that exists as a real user.
119169544Seric **
119269544Seric ** This is to handle the case of:
119369569Seric ** awc: Andrew.Chang
119469569Seric ** Andrew.Chang: awc@mail.server
119569544Seric ** which is a problem only on mail.server.
119669544Seric **
119769544Seric ** Parameters:
119869544Seric ** a -- the address to check.
119969544Seric ** e -- the current envelope.
120069544Seric **
120169544Seric ** Returns:
120269544Seric ** The address that should be retained.
120369544Seric */
120469544Seric
120569544Seric ADDRESS *
self_reference(a,e)120669544Seric self_reference(a, e)
120769544Seric ADDRESS *a;
120869544Seric ENVELOPE *e;
120969544Seric {
121069544Seric ADDRESS *b; /* top entry in self ref loop */
121169544Seric ADDRESS *c; /* entry that point to a real mail box */
121269544Seric
121369544Seric if (tTd(27, 1))
121469544Seric printf("self_reference(%s)\n", a->q_paddr);
121569544Seric
121669544Seric for (b = a->q_alias; b != NULL; b = b->q_alias)
121769544Seric {
121869544Seric if (sameaddr(a, b))
121969544Seric break;
122069544Seric }
122169544Seric
122269544Seric if (b == NULL)
122369544Seric {
122469544Seric if (tTd(27, 1))
122569544Seric printf("\t... no self ref\n");
122669544Seric return NULL;
122769544Seric }
122869544Seric
122969544Seric /*
123069544Seric ** Pick the first address that resolved to a real mail box
123169544Seric ** i.e has a pw entry. The returned value will be marked
123269544Seric ** QSELFREF in recipient(), which in turn will disable alias()
123369544Seric ** from marking it QDONTSEND, which mean it will be used
123469544Seric ** as a deliverable address.
123569544Seric **
123669544Seric ** The 2 key thing to note here are:
123769544Seric ** 1) we are in a recursive call sequence:
123869544Seric ** alias->sentolist->recipient->alias
123969544Seric ** 2) normally, when we return back to alias(), the address
124069544Seric ** will be marked QDONTSEND, since alias() assumes the
124169544Seric ** expanded form will be used instead of the current address.
124269544Seric ** This behaviour is turned off if the address is marked
124369544Seric ** QSELFREF We set QSELFREF when we return to recipient().
124469544Seric */
124569544Seric
124669544Seric c = a;
124769544Seric while (c != NULL)
124869544Seric {
124969544Seric if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
125069544Seric {
125169544Seric if (tTd(27, 2))
125269544Seric printf("\t... getpwnam(%s)... ", c->q_user);
125369544Seric if (sm_getpwnam(c->q_user) != NULL)
125469544Seric {
125569544Seric if (tTd(27, 2))
125669544Seric printf("found\n");
125769544Seric
125869544Seric /* ought to cache results here */
125969621Seric if (sameaddr(b, c))
126069621Seric return b;
126169621Seric else
126269621Seric return c;
126369544Seric }
126469544Seric if (tTd(27, 2))
126569544Seric printf("failed\n");
126669544Seric }
126769544Seric c = c->q_alias;
126869544Seric }
126969544Seric
127069544Seric if (tTd(27, 1))
127169544Seric printf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
127269544Seric
127369544Seric return NULL;
127469544Seric }
1275