Annotation of 42BSD/usr.lib/sendmail/src/recipient.c, revision 1.1.1.1

1.1       root        1: # include <pwd.h>
                      2: # include "sendmail.h"
                      3: # include <sys/stat.h>
                      4: 
                      5: SCCSID(@(#)recipient.c 4.1             7/25/83);
                      6: 
                      7: /*
                      8: **  SENDTOLIST -- Designate a send list.
                      9: **
                     10: **     The parameter is a comma-separated list of people to send to.
                     11: **     This routine arranges to send to all of them.
                     12: **
                     13: **     Parameters:
                     14: **             list -- the send list.
                     15: **             ctladdr -- the address template for the person to
                     16: **                     send to -- effective uid/gid are important.
                     17: **                     This is typically the alias that caused this
                     18: **                     expansion.
                     19: **             sendq -- a pointer to the head of a queue to put
                     20: **                     these people into.
                     21: **
                     22: **     Returns:
                     23: **             none
                     24: **
                     25: **     Side Effects:
                     26: **             none.
                     27: */
                     28: 
                     29: # define MAXRCRSN      10
                     30: 
                     31: sendtolist(list, ctladdr, sendq)
                     32:        char *list;
                     33:        ADDRESS *ctladdr;
                     34:        ADDRESS **sendq;
                     35: {
                     36:        register char *p;
                     37:        register ADDRESS *al;   /* list of addresses to send to */
                     38:        bool firstone;          /* set on first address sent */
                     39:        bool selfref;           /* set if this list includes ctladdr */
                     40:        char delimiter;         /* the address delimiter */
                     41: 
                     42: # ifdef DEBUG
                     43:        if (tTd(25, 1))
                     44:        {
                     45:                printf("sendto: %s\n   ctladdr=", list);
                     46:                printaddr(ctladdr, FALSE);
                     47:        }
                     48: # endif DEBUG
                     49: 
                     50:        /* heuristic to determine old versus new style addresses */
                     51:        if (ctladdr == NULL &&
                     52:            (index(list, ',') != NULL || index(list, ';') != NULL ||
                     53:             index(list, '<') != NULL || index(list, '(') != NULL))
                     54:                CurEnv->e_flags &= ~EF_OLDSTYLE;
                     55:        delimiter = ' ';
                     56:        if (!bitset(EF_OLDSTYLE, CurEnv->e_flags) || ctladdr != NULL)
                     57:                delimiter = ',';
                     58: 
                     59:        firstone = TRUE;
                     60:        selfref = FALSE;
                     61:        al = NULL;
                     62: 
                     63:        for (p = list; *p != '\0'; )
                     64:        {
                     65:                register ADDRESS *a;
                     66:                extern char *DelimChar;         /* defined in prescan */
                     67: 
                     68:                /* parse the address */
                     69:                while (isspace(*p) || *p == ',')
                     70:                        p++;
                     71:                a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter);
                     72:                p = DelimChar;
                     73:                if (a == NULL)
                     74:                        continue;
                     75:                a->q_next = al;
                     76:                a->q_alias = ctladdr;
                     77: 
                     78:                /* see if this should be marked as a primary address */
                     79:                if (ctladdr == NULL ||
                     80:                    (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags)))
                     81:                        a->q_flags |= QPRIMARY;
                     82: 
                     83:                /* put on send queue or suppress self-reference */
                     84:                if (ctladdr != NULL && sameaddr(ctladdr, a))
                     85:                        selfref = TRUE;
                     86:                else
                     87:                        al = a;
                     88:                firstone = FALSE;
                     89:        }
                     90: 
                     91:        /* if this alias doesn't include itself, delete ctladdr */
                     92:        if (!selfref && ctladdr != NULL)
                     93:                ctladdr->q_flags |= QDONTSEND;
                     94: 
                     95:        /* arrange to send to everyone on the local send list */
                     96:        while (al != NULL)
                     97:        {
                     98:                register ADDRESS *a = al;
                     99:                extern ADDRESS *recipient();
                    100: 
                    101:                al = a->q_next;
                    102:                a = recipient(a, sendq);
                    103: 
                    104:                /* arrange to inherit full name */
                    105:                if (a->q_fullname == NULL && ctladdr != NULL)
                    106:                        a->q_fullname = ctladdr->q_fullname;
                    107:        }
                    108: 
                    109:        CurEnv->e_to = NULL;
                    110: }
                    111: /*
                    112: **  RECIPIENT -- Designate a message recipient
                    113: **
                    114: **     Saves the named person for future mailing.
                    115: **
                    116: **     Parameters:
                    117: **             a -- the (preparsed) address header for the recipient.
                    118: **             sendq -- a pointer to the head of a queue to put the
                    119: **                     recipient in.  Duplicate supression is done
                    120: **                     in this queue.
                    121: **
                    122: **     Returns:
                    123: **             The actual address in the queue.  This will be "a" if
                    124: **             the address is not a duplicate, else the original address.
                    125: **
                    126: **     Side Effects:
                    127: **             none.
                    128: */
                    129: 
                    130: ADDRESS *
                    131: recipient(a, sendq)
                    132:        register ADDRESS *a;
                    133:        register ADDRESS **sendq;
                    134: {
                    135:        register ADDRESS *q;
                    136:        ADDRESS **pq;
                    137:        register struct mailer *m;
                    138:        register char *p;
                    139:        bool quoted = FALSE;            /* set if the addr has a quote bit */
                    140:        char buf[MAXNAME];              /* unquoted image of the user name */
                    141:        extern ADDRESS *getctladdr();
                    142:        extern bool safefile();
                    143: 
                    144:        CurEnv->e_to = a->q_paddr;
                    145:        m = a->q_mailer;
                    146:        errno = 0;
                    147: # ifdef DEBUG
                    148:        if (tTd(26, 1))
                    149:        {
                    150:                printf("\nrecipient: ");
                    151:                printaddr(a, FALSE);
                    152:        }
                    153: # endif DEBUG
                    154: 
                    155:        /* break aliasing loops */
                    156:        if (AliasLevel > MAXRCRSN)
                    157:        {
                    158:                usrerr("aliasing/forwarding loop broken");
                    159:                return (a);
                    160:        }
                    161: 
                    162:        /*
                    163:        **  Finish setting up address structure.
                    164:        */
                    165: 
                    166:        a->q_timeout = TimeOut;
                    167: 
                    168:        (void) strcpy(buf, a->q_user);
                    169:        for (p = buf; *p != '\0' && !quoted; p++)
                    170:        {
                    171:                if (!isascii(*p) && (*p & 0377) != (SpaceSub & 0377))
                    172:                        quoted = TRUE;
                    173:        }
                    174:        stripquotes(buf, TRUE);
                    175: 
                    176:        /* do sickly crude mapping for program mailing, etc. */
                    177:        if (m == LocalMailer && buf[0] == '|')
                    178:        {
                    179:                a->q_mailer = m = ProgMailer;
                    180:                a->q_user++;
                    181:                if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail)
                    182:                {
                    183:                        usrerr("Cannot mail directly to programs");
                    184:                        a->q_flags |= QDONTSEND;
                    185:                }
                    186:        }
                    187: 
                    188:        /*
                    189:        **  Look up this person in the recipient list.
                    190:        **      If they are there already, return, otherwise continue.
                    191:        **      If the list is empty, just add it.  Notice the cute
                    192:        **      hack to make from addresses suppress things correctly:
                    193:        **      the QDONTSEND bit will be set in the send list.
                    194:        **      [Please note: the emphasis is on "hack."]
                    195:        */
                    196: 
                    197:        for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
                    198:        {
                    199:                if (!ForceMail && sameaddr(q, a))
                    200:                {
                    201: # ifdef DEBUG
                    202:                        if (tTd(26, 1))
                    203:                        {
                    204:                                printf("%s in sendq: ", a->q_paddr);
                    205:                                printaddr(q, FALSE);
                    206:                        }
                    207: # endif DEBUG
                    208:                        if (!bitset(QDONTSEND, a->q_flags))
                    209:                                message(Arpa_Info, "duplicate suppressed");
                    210:                        if (!bitset(QPRIMARY, q->q_flags))
                    211:                                q->q_flags |= a->q_flags;
                    212:                        return (q);
                    213:                }
                    214:        }
                    215: 
                    216:        /* add address on list */
                    217:        *pq = a;
                    218:        a->q_next = NULL;
                    219: 
                    220:        /*
                    221:        **  Alias the name and handle :include: specs.
                    222:        */
                    223: 
                    224:        if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags))
                    225:        {
                    226:                if (strncmp(a->q_user, ":include:", 9) == 0)
                    227:                {
                    228:                        a->q_flags |= QDONTSEND;
                    229:                        if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail)
                    230:                                usrerr("Cannot mail directly to :include:s");
                    231:                        else
                    232:                        {
                    233:                                message(Arpa_Info, "including file %s", &a->q_user[9]);
                    234:                                include(&a->q_user[9], " sending", a, sendq);
                    235:                        }
                    236:                }
                    237:                else
                    238:                        alias(a, sendq);
                    239:        }
                    240: 
                    241:        /*
                    242:        **  If the user is local and still being sent, verify that
                    243:        **  the address is good.  If it is, try to forward.
                    244:        **  If the address is already good, we have a forwarding
                    245:        **  loop.  This can be broken by just sending directly to
                    246:        **  the user (which is probably correct anyway).
                    247:        */
                    248: 
                    249:        if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer)
                    250:        {
                    251:                struct stat stb;
                    252:                extern bool writable();
                    253: 
                    254:                /* see if this is to a file */
                    255:                if (buf[0] == '/')
                    256:                {
                    257:                        p = rindex(buf, '/');
                    258:                        /* check if writable or creatable */
                    259:                        if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail)
                    260:                        {
                    261:                                usrerr("Cannot mail directly to files");
                    262:                                a->q_flags |= QDONTSEND;
                    263:                        }
                    264:                        else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) :
                    265:                            (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC)))
                    266:                        {
                    267:                                a->q_flags |= QBADADDR;
                    268:                                giveresponse(EX_CANTCREAT, m, CurEnv);
                    269:                        }
                    270:                }
                    271:                else
                    272:                {
                    273:                        register struct passwd *pw;
                    274:                        extern struct passwd *finduser();
                    275: 
                    276:                        /* warning -- finduser may trash buf */
                    277:                        pw = finduser(buf);
                    278:                        if (pw == NULL)
                    279:                        {
                    280:                                a->q_flags |= QBADADDR;
                    281:                                giveresponse(EX_NOUSER, m, CurEnv);
                    282:                        }
                    283:                        else
                    284:                        {
                    285:                                char nbuf[MAXNAME];
                    286: 
                    287:                                if (strcmp(a->q_user, pw->pw_name) != 0)
                    288:                                {
                    289:                                        a->q_user = newstr(pw->pw_name);
                    290:                                        (void) strcpy(buf, pw->pw_name);
                    291:                                }
                    292:                                a->q_home = newstr(pw->pw_dir);
                    293:                                a->q_uid = pw->pw_uid;
                    294:                                a->q_gid = pw->pw_gid;
                    295:                                a->q_flags |= QGOODUID;
                    296:                                buildfname(pw->pw_gecos, pw->pw_name, nbuf);
                    297:                                if (nbuf[0] != '\0')
                    298:                                        a->q_fullname = newstr(nbuf);
                    299:                                if (!quoted)
                    300:                                        forward(a, sendq);
                    301:                        }
                    302:                }
                    303:        }
                    304:        return (a);
                    305: }
                    306: /*
                    307: **  FINDUSER -- find the password entry for a user.
                    308: **
                    309: **     This looks a lot like getpwnam, except that it may want to
                    310: **     do some fancier pattern matching in /etc/passwd.
                    311: **
                    312: **     This routine contains most of the time of many sendmail runs.
                    313: **     It deserves to be optimized.
                    314: **
                    315: **     Parameters:
                    316: **             name -- the name to match against.
                    317: **
                    318: **     Returns:
                    319: **             A pointer to a pw struct.
                    320: **             NULL if name is unknown or ambiguous.
                    321: **
                    322: **     Side Effects:
                    323: **             may modify name.
                    324: */
                    325: 
                    326: struct passwd *
                    327: finduser(name)
                    328:        char *name;
                    329: {
                    330:        extern struct passwd *getpwent();
                    331:        register struct passwd *pw;
                    332:        register char *p;
                    333: 
                    334:        /*
                    335:        **  Make name canonical.
                    336:        */
                    337: 
                    338:        for (p = name; *p != '\0'; p++)
                    339:        {
                    340:                if (*p == (SpaceSub & 0177) || *p == '_')
                    341:                        *p = ' ';
                    342:        }
                    343: 
                    344:        /* look up this login name */
                    345:        if ((pw = getpwnam(name)) != NULL)
                    346:                return (pw);
                    347: 
                    348:        /* search for a matching full name instead */
                    349:        setpwent();
                    350:        while ((pw = getpwent()) != NULL)
                    351:        {
                    352:                char buf[MAXNAME];
                    353:                extern bool sameword();
                    354: 
                    355:                if (strcmp(pw->pw_name, name) == 0)
                    356:                        return (pw);
                    357:                buildfname(pw->pw_gecos, pw->pw_name, buf);
                    358:                if (index(buf, ' ') != NULL && sameword(buf, name))
                    359:                {
                    360:                        message(Arpa_Info, "sending to login name %s", pw->pw_name);
                    361:                        return (pw);
                    362:                }
                    363:        }
                    364:        return (NULL);
                    365: }
                    366: /*
                    367: **  WRITABLE -- predicate returning if the file is writable.
                    368: **
                    369: **     This routine must duplicate the algorithm in sys/fio.c.
                    370: **     Unfortunately, we cannot use the access call since we
                    371: **     won't necessarily be the real uid when we try to
                    372: **     actually open the file.
                    373: **
                    374: **     Notice that ANY file with ANY execute bit is automatically
                    375: **     not writable.  This is also enforced by mailfile.
                    376: **
                    377: **     Parameters:
                    378: **             s -- pointer to a stat struct for the file.
                    379: **
                    380: **     Returns:
                    381: **             TRUE -- if we will be able to write this file.
                    382: **             FALSE -- if we cannot write this file.
                    383: **
                    384: **     Side Effects:
                    385: **             none.
                    386: */
                    387: 
                    388: bool
                    389: writable(s)
                    390:        register struct stat *s;
                    391: {
                    392:        int euid, egid;
                    393:        int bits;
                    394: 
                    395:        if (bitset(0111, s->st_mode))
                    396:                return (FALSE);
                    397:        euid = getruid();
                    398:        egid = getrgid();
                    399:        if (geteuid() == 0)
                    400:        {
                    401:                if (bitset(S_ISUID, s->st_mode))
                    402:                        euid = s->st_uid;
                    403:                if (bitset(S_ISGID, s->st_mode))
                    404:                        egid = s->st_gid;
                    405:        }
                    406: 
                    407:        if (euid == 0)
                    408:                return (TRUE);
                    409:        bits = S_IWRITE;
                    410:        if (euid != s->st_uid)
                    411:        {
                    412:                bits >>= 3;
                    413:                if (egid != s->st_gid)
                    414:                        bits >>= 3;
                    415:        }
                    416:        return ((s->st_mode & bits) != 0);
                    417: }
                    418: /*
                    419: **  INCLUDE -- handle :include: specification.
                    420: **
                    421: **     Parameters:
                    422: **             fname -- filename to include.
                    423: **             msg -- message to print in verbose mode.
                    424: **             ctladdr -- address template to use to fill in these
                    425: **                     addresses -- effective user/group id are
                    426: **                     the important things.
                    427: **             sendq -- a pointer to the head of the send queue
                    428: **                     to put these addresses in.
                    429: **
                    430: **     Returns:
                    431: **             none.
                    432: **
                    433: **     Side Effects:
                    434: **             reads the :include: file and sends to everyone
                    435: **             listed in that file.
                    436: */
                    437: 
                    438: include(fname, msg, ctladdr, sendq)
                    439:        char *fname;
                    440:        char *msg;
                    441:        ADDRESS *ctladdr;
                    442:        ADDRESS **sendq;
                    443: {
                    444:        char buf[MAXLINE];
                    445:        register FILE *fp;
                    446:        char *oldto = CurEnv->e_to;
                    447:        char *oldfilename = FileName;
                    448:        int oldlinenumber = LineNumber;
                    449: 
                    450:        fp = fopen(fname, "r");
                    451:        if (fp == NULL)
                    452:        {
                    453:                usrerr("Cannot open %s", fname);
                    454:                return;
                    455:        }
                    456:        if (getctladdr(ctladdr) == NULL)
                    457:        {
                    458:                struct stat st;
                    459: 
                    460:                if (fstat(fileno(fp), &st) < 0)
                    461:                        syserr("Cannot fstat %s!", fname);
                    462:                ctladdr->q_uid = st.st_uid;
                    463:                ctladdr->q_gid = st.st_gid;
                    464:                ctladdr->q_flags |= QGOODUID;
                    465:        }
                    466: 
                    467:        /* read the file -- each line is a comma-separated list. */
                    468:        FileName = fname;
                    469:        LineNumber = 0;
                    470:        while (fgets(buf, sizeof buf, fp) != NULL)
                    471:        {
                    472:                register char *p = index(buf, '\n');
                    473: 
                    474:                if (p != NULL)
                    475:                        *p = '\0';
                    476:                if (buf[0] == '\0')
                    477:                        continue;
                    478:                CurEnv->e_to = oldto;
                    479:                message(Arpa_Info, "%s to %s", msg, buf);
                    480:                AliasLevel++;
                    481:                sendtolist(buf, ctladdr, sendq);
                    482:                AliasLevel--;
                    483:        }
                    484: 
                    485:        (void) fclose(fp);
                    486:        FileName = oldfilename;
                    487:        LineNumber = oldlinenumber;
                    488: }
                    489: /*
                    490: **  SENDTOARGV -- send to an argument vector.
                    491: **
                    492: **     Parameters:
                    493: **             argv -- argument vector to send to.
                    494: **
                    495: **     Returns:
                    496: **             none.
                    497: **
                    498: **     Side Effects:
                    499: **             puts all addresses on the argument vector onto the
                    500: **                     send queue.
                    501: */
                    502: 
                    503: sendtoargv(argv)
                    504:        register char **argv;
                    505: {
                    506:        register char *p;
                    507:        extern bool sameword();
                    508: 
                    509:        while ((p = *argv++) != NULL)
                    510:        {
                    511:                if (argv[0] != NULL && argv[1] != NULL && sameword(argv[0], "at"))
                    512:                {
                    513:                        char nbuf[MAXNAME];
                    514: 
                    515:                        if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf)
                    516:                                usrerr("address overflow");
                    517:                        else
                    518:                        {
                    519:                                (void) strcpy(nbuf, p);
                    520:                                (void) strcat(nbuf, "@");
                    521:                                (void) strcat(nbuf, argv[1]);
                    522:                                p = newstr(nbuf);
                    523:                                argv += 2;
                    524:                        }
                    525:                }
                    526:                sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
                    527:        }
                    528: }
                    529: /*
                    530: **  GETCTLADDR -- get controlling address from an address header.
                    531: **
                    532: **     If none, get one corresponding to the effective userid.
                    533: **
                    534: **     Parameters:
                    535: **             a -- the address to find the controller of.
                    536: **
                    537: **     Returns:
                    538: **             the controlling address.
                    539: **
                    540: **     Side Effects:
                    541: **             none.
                    542: */
                    543: 
                    544: ADDRESS *
                    545: getctladdr(a)
                    546:        register ADDRESS *a;
                    547: {
                    548:        while (a != NULL && !bitset(QGOODUID, a->q_flags))
                    549:                a = a->q_alias;
                    550:        return (a);
                    551: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.