clean up ordering; don't lose stuff that arrives during uiomove
[unix-history] / usr / src / usr.sbin / sendmail / src / alias.c
CommitLineData
d185cb11
DF
1/*
2** Sendmail
3** Copyright (c) 1983 Eric P. Allman
4** Berkeley, California
5**
6** Copyright (c) 1983 Regents of the University of California.
7** All rights reserved. The Berkeley software License Agreement
8** specifies the terms and conditions for redistribution.
9*/
10
b3cbe40f 11# include <pwd.h>
9c3f729b
EA
12# include <sys/types.h>
13# include <sys/stat.h>
7bdc419c 14# include <signal.h>
e6e345fa 15# include <errno.h>
96faada8 16# include "sendmail.h"
e6e345fa
EA
17# ifdef FLOCK
18# include <sys/file.h>
19# endif FLOCK
b3cbe40f 20
1cc8903f
EA
21#ifndef lint
22# ifdef DBM
23static char SccsId[] = "@(#)alias.c 5.11 (Berkeley) %G% (with DBM)";
24# else DBM
25static char SccsId[] = "@(#)alias.c 5.11 (Berkeley) %G% (without DBM)";
26# endif DBM
27#endif not lint
28
916b3375 29
b3cbe40f
EA
30/*
31** ALIAS -- Compute aliases.
32**
7338e3d4
EA
33** Scans the alias file for an alias for the given address.
34** If found, it arranges to deliver to the alias list instead.
35** Uses libdbm database if -DDBM.
b3cbe40f
EA
36**
37** Parameters:
bdfaa762 38** a -- address to alias.
d4f42161
EA
39** sendq -- a pointer to the head of the send queue
40** to put the aliases in.
b3cbe40f
EA
41**
42** Returns:
43** none
44**
45** Side Effects:
9e3c0a28 46** Aliases found are expanded.
b3cbe40f 47**
b3cbe40f
EA
48** Notes:
49** If NoAlias (the "-n" flag) is set, no aliasing is
50** done.
51**
52** Deficiencies:
53** It should complain about names that are aliased to
54** nothing.
b3cbe40f
EA
55*/
56
57
c9b9c7a2 58#ifdef DBM
a530c75f
EA
59typedef struct
60{
61 char *dptr;
f4dbf345
EA
62 int dsize;
63} DATUM;
f4dbf345 64extern DATUM fetch();
c9b9c7a2 65#endif DBM
b3cbe40f 66
d4f42161 67alias(a, sendq)
bdfaa762 68 register ADDRESS *a;
d4f42161 69 ADDRESS **sendq;
b3cbe40f 70{
29871fef 71 register char *p;
abae7b2d 72 extern ADDRESS *sendto();
35cc3fad 73 extern char *aliaslookup();
b3cbe40f 74
b3cbe40f 75# ifdef DEBUG
9678c96d 76 if (tTd(27, 1))
cdb17311 77 printf("alias(%s)\n", a->q_paddr);
b3cbe40f
EA
78# endif
79
cdb17311
EA
80 /* don't realias already aliased names */
81 if (bitset(QDONTSEND, a->q_flags))
82 return;
83
2654b031 84 CurEnv->e_to = a->q_paddr;
cdb17311 85
74c5fe7c
EA
86 /*
87 ** Look up this name
88 */
89
2e3062fe
EA
90 if (NoAlias)
91 p = NULL;
92 else
93 p = aliaslookup(a->q_user);
cdb17311
EA
94 if (p == NULL)
95 return;
b3cbe40f 96
d916f0ca 97 /*
cdb17311
EA
98 ** Match on Alias.
99 ** Deliver to the target list.
d916f0ca
EA
100 */
101
cdb17311 102# ifdef DEBUG
9678c96d 103 if (tTd(27, 1))
cdb17311
EA
104 printf("%s (%s, %s) aliased to %s\n",
105 a->q_paddr, a->q_host, a->q_user, p);
106# endif
91f69adf 107 message(Arpa_Info, "aliased to %s", p);
cdb17311 108 AliasLevel++;
abae7b2d 109 a->q_child = sendto(p, 1, a, 0);
cdb17311
EA
110 AliasLevel--;
111}
112\f/*
35cc3fad
EA
113** ALIASLOOKUP -- look up a name in the alias file.
114**
115** Parameters:
116** name -- the name to look up.
117**
118** Returns:
119** the value of name.
120** NULL if unknown.
121**
122** Side Effects:
123** none.
124**
125** Warnings:
126** The return value will be trashed across calls.
127*/
128
129char *
130aliaslookup(name)
131 char *name;
132{
133# ifdef DBM
134 DATUM rhs, lhs;
135
136 /* create a key for fetch */
137 lhs.dptr = name;
138 lhs.dsize = strlen(name) + 1;
139 rhs = fetch(lhs);
140 return (rhs.dptr);
141# else DBM
142 register STAB *s;
143
144 s = stab(name, ST_ALIAS, ST_FIND);
145 if (s == NULL)
146 return (NULL);
147 return (s->s_alias);
148# endif DBM
149}
150\f/*
cdb17311
EA
151** INITALIASES -- initialize for aliasing
152**
153** Very different depending on whether we are running DBM or not.
154**
155** Parameters:
156** aliasfile -- location of aliases.
f4dbf345 157** init -- if set and if DBM, initialize the DBM files.
cdb17311
EA
158**
159** Returns:
160** none.
161**
162** Side Effects:
163** initializes aliases:
164** if DBM: opens the database.
165** if ~DBM: reads the aliases into the symbol table.
166*/
167
f4dbf345
EA
168# define DBMMODE 0666
169
170initaliases(aliasfile, init)
cdb17311 171 char *aliasfile;
f4dbf345 172 bool init;
cdb17311 173{
7338e3d4 174#ifdef DBM
7bdc419c 175 int atcnt;
d6b27179 176 time_t modtime;
9327783c
EA
177 bool automatic = FALSE;
178 char buf[MAXNAME];
7338e3d4
EA
179#endif DBM
180 struct stat stb;
d6b27179 181
bb09c502 182 if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
7bdc419c 183 {
9327783c
EA
184 if (aliasfile != NULL && init)
185 syserr("Cannot open %s", aliasfile);
7bdc419c 186 NoAlias = TRUE;
70faa7c8 187 errno = 0;
7bdc419c
EA
188 return;
189 }
190
d5fe2834 191# ifdef DBM
7bdc419c
EA
192 /*
193 ** Check to see that the alias file is complete.
194 ** If not, we will assume that someone died, and it is up
195 ** to us to rebuild it.
196 */
197
a1a07282
EA
198 if (!init)
199 dbminit(aliasfile);
560a80d9
EA
200 atcnt = SafeAlias * 2;
201 if (atcnt > 0)
202 {
203 while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
a1a07282
EA
204 {
205 /*
206 ** Reinitialize alias file in case the new
207 ** one is mv'ed in instead of cp'ed in.
208 **
209 ** Only works with new DBM -- old one will
210 ** just consume file descriptors forever.
211 ** If you have a dbmclose() it can be
212 ** added before the sleep(30).
213 */
214
560a80d9 215 sleep(30);
a1a07282
EA
216# ifdef NDBM
217 dbminit(aliasfile);
218# endif NDBM
219 }
560a80d9
EA
220 }
221 else
222 atcnt = 1;
7bdc419c 223
d6b27179
EA
224 /*
225 ** See if the DBM version of the file is out of date with
226 ** the text version. If so, go into 'init' mode automatically.
227 ** This only happens if our effective userid owns the DBM
f9ce44de 228 ** version or if the mode of the database is 666 -- this
d6b27179
EA
229 ** is an attempt to avoid protection problems. Note the
230 ** unpalatable hack to see if the stat succeeded.
231 */
232
d6b27179
EA
233 modtime = stb.st_mtime;
234 (void) strcpy(buf, aliasfile);
235 (void) strcat(buf, ".pag");
236 stb.st_ino = 0;
f12e5a74 237 if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
f4dbf345 238 {
70faa7c8 239 errno = 0;
4871a357 240 if (AutoRebuild && stb.st_ino != 0 &&
7338e3d4 241 ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid()))
d6b27179
EA
242 {
243 init = TRUE;
9327783c 244 automatic = TRUE;
91f69adf 245 message(Arpa_Info, "rebuilding alias database");
2e3062fe
EA
246#ifdef LOG
247 if (LogLevel >= 7)
248 syslog(LOG_INFO, "rebuilding alias database");
249#endif LOG
d6b27179
EA
250 }
251 else
252 {
f12e5a74 253#ifdef LOG
2e3062fe
EA
254 if (LogLevel >= 7)
255 syslog(LOG_INFO, "alias database out of date");
f12e5a74 256#endif LOG
d6b27179
EA
257 message(Arpa_Info, "Warning: alias database out of date");
258 }
259 }
f4dbf345 260
d6b27179
EA
261
262 /*
7bdc419c 263 ** If necessary, load the DBM file.
d6b27179
EA
264 ** If running without DBM, load the symbol table.
265 */
266
f4dbf345 267 if (init)
7bdc419c 268 {
9327783c
EA
269#ifdef LOG
270 if (LogLevel >= 6)
271 {
272 extern char *username();
273
274 syslog(LOG_NOTICE, "alias database %srebuilt by %s",
275 automatic ? "auto" : "", username());
276 }
277#endif LOG
f4dbf345 278 readaliases(aliasfile, TRUE);
7bdc419c 279 }
cdb17311 280# else DBM
f4dbf345
EA
281 readaliases(aliasfile, init);
282# endif DBM
283}
284\f/*
285** READALIASES -- read and process the alias file.
286**
287** This routine implements the part of initaliases that occurs
288** when we are not going to use the DBM stuff.
289**
290** Parameters:
291** aliasfile -- the pathname of the alias file master.
292** init -- if set, initialize the DBM stuff.
293**
294** Returns:
295** none.
296**
297** Side Effects:
298** Reads aliasfile into the symbol table.
299** Optionally, builds the .dir & .pag files.
300*/
301
302static
303readaliases(aliasfile, init)
304 char *aliasfile;
305 bool init;
306{
cdb17311 307 register char *p;
41173b8f 308 char *lhs;
cdb17311
EA
309 char *rhs;
310 bool skipping;
7338e3d4 311 int naliases, bytes, longest;
9e25d1f0 312 FILE *af;
e6e345fa 313 int (*oldsigint)();
7338e3d4 314 ADDRESS al, bl;
9e25d1f0 315 register STAB *s;
7338e3d4 316 char line[BUFSIZ];
cdb17311
EA
317
318 if ((af = fopen(aliasfile, "r")) == NULL)
d916f0ca 319 {
cdb17311 320# ifdef DEBUG
9678c96d 321 if (tTd(27, 1))
9e25d1f0 322 printf("Can't open %s\n", aliasfile);
cdb17311
EA
323# endif
324 errno = 0;
325 NoAlias++;
326 return;
327 }
74c5fe7c 328
e6e345fa
EA
329# ifdef DBM
330# ifdef FLOCK
331 /* see if someone else is rebuilding the alias file already */
332 if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
333 {
334 /* yes, they are -- wait until done and then return */
335 message(Arpa_Info, "Alias file is already being rebuilt");
336 if (OpMode != MD_INITALIAS)
337 {
338 /* wait for other rebuild to complete */
339 (void) flock(fileno(af), LOCK_EX);
340 }
03388044 341 (void) fclose(af);
e6e345fa
EA
342 errno = 0;
343 return;
344 }
345# endif FLOCK
346# endif DBM
347
348 /*
349 ** If initializing, create the new DBM files.
350 */
351
352 if (init)
353 {
354 oldsigint = signal(SIGINT, SIG_IGN);
355 (void) strcpy(line, aliasfile);
356 (void) strcat(line, ".dir");
357 if (close(creat(line, DBMMODE)) < 0)
358 {
359 syserr("cannot make %s", line);
360 (void) signal(SIGINT, oldsigint);
361 return;
362 }
a1a07282 363 dbminit(aliasfile);
e6e345fa
EA
364 (void) strcpy(line, aliasfile);
365 (void) strcat(line, ".pag");
366 if (close(creat(line, DBMMODE)) < 0)
367 {
368 syserr("cannot make %s", line);
369 (void) signal(SIGINT, oldsigint);
370 return;
371 }
372 }
373
74c5fe7c
EA
374 /*
375 ** Read and interpret lines
376 */
377
7338e3d4
EA
378 FileName = aliasfile;
379 LineNumber = 0;
d6b27179 380 naliases = bytes = longest = 0;
cdb17311
EA
381 skipping = FALSE;
382 while (fgets(line, sizeof (line), af) != NULL)
383 {
d6b27179
EA
384 int lhssize, rhssize;
385
7338e3d4 386 LineNumber++;
3312f93c
EA
387 p = index(line, '\n');
388 if (p != NULL)
389 *p = '\0';
cdb17311
EA
390 switch (line[0])
391 {
392 case '#':
cdb17311
EA
393 case '\0':
394 skipping = FALSE;
395 continue;
bdfaa762 396
cdb17311
EA
397 case ' ':
398 case '\t':
399 if (!skipping)
7338e3d4 400 syserr("Non-continuation line starts with space");
cdb17311 401 skipping = TRUE;
bdfaa762 402 continue;
cdb17311
EA
403 }
404 skipping = FALSE;
bdfaa762 405
74c5fe7c
EA
406 /*
407 ** Process the LHS
41173b8f 408 **
74c5fe7c 409 ** Find the final colon, and parse the address.
41173b8f
EA
410 ** It should resolve to a local name.
411 **
412 ** Alternatively, it can be "@hostname" for host
413 ** aliases -- all we do here is map case. Hostname
414 ** need not be a single token.
74c5fe7c
EA
415 */
416
cdb17311 417 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
bdfaa762 418 continue;
41173b8f 419 if (*p != ':')
cdb17311 420 {
1bcdf0a2 421 syserr("%s, line %d: syntax error", aliasfile, lineno);
bdfaa762 422 continue;
cdb17311 423 }
41173b8f
EA
424 *p++ = '\0';
425 if (line[0] == '@')
cdb17311 426 {
41173b8f
EA
427 /* a host alias */
428 makelower(line);
429 lhs = line;
430 }
431 else
432 {
433 /* a user alias */
434 if (parseaddr(line, &al, 1, ':') == NULL)
435 {
436 syserr("illegal alias name");
437 continue;
438 }
439 loweraddr(&al);
440 if (al.q_mailer != LocalMailer)
441 {
442 syserr("cannot alias non-local names");
443 continue;
444 }
445 lhs = al.q_user;
cdb17311 446 }
74c5fe7c
EA
447
448 /*
449 ** Process the RHS.
450 ** 'al' is the internal form of the LHS address.
451 ** 'p' points to the text of the RHS.
1bcdf0a2
EA
452 ** 'p' may begin with a colon (i.e., the
453 ** separator was "::") which will use the
454 ** first address as the person to send
455 ** errors to -- i.e., designates the
456 ** list maintainer.
74c5fe7c
EA
457 */
458
1bcdf0a2
EA
459 if (*p == ':')
460 {
461 ADDRESS *maint;
462
463 while (isspace(*++p))
464 continue;
465 rhs = p;
466 while (*p != '\0' && *p != ',')
467 p++;
468 if (*p != ',')
469 goto syntaxerr;
470 *p++ = '\0';
471 maint = parse(p, (ADDRESS *) NULL, 1);
472 if (maint == NULL)
473 syserr("Illegal list maintainer for list %s", al.q_user);
474 else if (CurEnv->e_returnto == &CurEnv->e_from)
475 {
476 CurEnv->e_returnto = maint;
477 MailBack++;
478 }
479 }
480
cdb17311 481 rhs = p;
cdb17311
EA
482 for (;;)
483 {
484 register char c;
d916f0ca 485
1e963db5 486 if (init && CheckAliases)
cdb17311 487 {
f4dbf345 488 /* do parsing & compression of addresses */
3312f93c 489 while (*p != '\0')
cdb17311 490 {
3312f93c
EA
491 extern char *DelimChar;
492
493 while (isspace(*p) || *p == ',')
c49d661c 494 p++;
3312f93c
EA
495 if (*p == '\0')
496 break;
497 if (parseaddr(p, &bl, -1, ',') == NULL)
498 usrerr("%s... bad address", p);
499 p = DelimChar;
cdb17311 500 }
cdb17311 501 }
f4dbf345 502 else
634c8ff3 503 {
34fe0a9b
EA
504 p = &p[strlen(p)];
505 if (p[-1] == '\n')
506 *--p = '\0';
634c8ff3 507 }
d916f0ca 508
cdb17311 509 /* see if there should be a continuation line */
9e25d1f0
EA
510 c = fgetc(af);
511 if (!feof(af))
74c5fe7c 512 (void) ungetc(c, af);
9e25d1f0 513 if (c != ' ' && c != '\t')
cdb17311
EA
514 break;
515
516 /* read continuation line */
cdb17311
EA
517 if (fgets(p, sizeof line - (p - line), af) == NULL)
518 break;
7338e3d4 519 LineNumber++;
cdb17311 520 }
74c5fe7c
EA
521
522 /*
523 ** Insert alias into symbol table or DBM file
524 */
525
41173b8f 526 lhssize = strlen(lhs) + 1;
d6b27179
EA
527 rhssize = strlen(rhs) + 1;
528
f4dbf345
EA
529# ifdef DBM
530 if (init)
531 {
532 DATUM key, content;
533
d6b27179 534 key.dsize = lhssize;
f4dbf345 535 key.dptr = al.q_user;
d6b27179 536 content.dsize = rhssize;
f4dbf345
EA
537 content.dptr = rhs;
538 store(key, content);
539 }
540 else
541# endif DBM
542 {
543 s = stab(al.q_user, ST_ALIAS, ST_ENTER);
544 s->s_alias = newstr(rhs);
545 }
d6b27179
EA
546
547 /* statistics */
548 naliases++;
549 bytes += lhssize + rhssize;
550 if (rhssize > longest)
551 longest = rhssize;
d916f0ca 552 }
e6e345fa
EA
553
554# ifdef DBM
555 if (init)
556 {
557 /* add the distinquished alias "@" */
558 DATUM key;
559
560 key.dsize = 2;
561 key.dptr = "@";
562 store(key, key);
563
564 /* restore the old signal */
565 (void) signal(SIGINT, oldsigint);
566 }
567# endif DBM
568
569 /* closing the alias file drops the lock */
cdb17311 570 (void) fclose(af);
2654b031 571 CurEnv->e_to = NULL;
7338e3d4 572 FileName = NULL;
91f69adf 573 message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
d6b27179 574 naliases, longest, bytes);
2e3062fe
EA
575# ifdef LOG
576 if (LogLevel >= 8)
577 syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
578 naliases, longest, bytes);
579# endif LOG
b3cbe40f
EA
580}
581\f/*
582** FORWARD -- Try to forward mail
583**
584** This is similar but not identical to aliasing.
585**
b3cbe40f 586** Parameters:
74c5fe7c
EA
587** user -- the name of the user who's mail we would like
588** to forward to. It must have been verified --
589** i.e., the q_home field must have been filled
590** in.
d4f42161
EA
591** sendq -- a pointer to the head of the send queue to
592** put this user's aliases in.
b3cbe40f
EA
593**
594** Returns:
cdb17311 595** none.
b3cbe40f
EA
596**
597** Side Effects:
9e3c0a28 598** New names are added to send queues.
b3cbe40f
EA
599*/
600
d4f42161 601forward(user, sendq)
a530c75f 602 ADDRESS *user;
d4f42161 603 ADDRESS **sendq;
b3cbe40f 604{
4bb4503e 605 char buf[60];
f6a0cc15 606 extern bool safefile();
56678245 607
cdb17311 608# ifdef DEBUG
9678c96d 609 if (tTd(27, 1))
cdb17311
EA
610 printf("forward(%s)\n", user->q_paddr);
611# endif DEBUG
612
179c1218 613 if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
cdb17311 614 return;
74c5fe7c
EA
615# ifdef DEBUG
616 if (user->q_home == NULL)
617 syserr("forward: no home");
618# endif DEBUG
56678245 619
56678245 620 /* good address -- look for .forward file in home */
7338e3d4 621 define('z', user->q_home, CurEnv);
a73ae8ac 622 expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
f6a0cc15 623 if (!safefile(buf, user->q_uid, S_IREAD))
cdb17311 624 return;
56678245
EA
625
626 /* we do have an address to forward to -- do it */
d4f42161 627 include(buf, "forwarding", user, sendq);
b3cbe40f 628}
41173b8f
EA
629\f/*
630** MAPHOST -- given a host description, produce a mapping.
631**
632** This is done by looking up the name in the alias file,
633** preceeded by an "@". This can be used for UUCP mapping.
634** For example, a call with {blia, ., UUCP} as arguments
635** might return {ucsfcgl, !, blia, ., UUCP} as the result.
636**
637** We first break the input into three parts -- before the
638** lookup, the lookup itself, and after the lookup. We
639** then do the lookup, concatenate them together, and rescan
640** the result.
641**
642** Parameters:
643** pvp -- the parameter vector to map.
644**
645** Returns:
646** The result of the mapping. If nothing found, it
647** should just concatenate the three parts together and
648** return that.
649**
650** Side Effects:
651** none.
652*/
653
654char **
655maphost(pvp)
656 char **pvp;
657{
658 register char **avp;
659 register char **bvp;
660 char *p;
661 char buf1[MAXNAME];
662 char buf2[MAXNAME];
663 char buf3[MAXNAME];
664 extern char **prescan();
665
666 /*
667 ** Extract the three parts of the input as strings.
668 */
669
670 /* find the part before the lookup */
671 for (bvp = pvp; *bvp != NULL && **bvp != MATCHLOOKUP; bvp++)
672 continue;
673 if (*bvp == NULL)
674 return (pvp);
675 p = *bvp;
676 *bvp = NULL;
677 cataddr(pvp, buf1, sizeof buf1);
678 *bvp++ = p;
679
680 /* find the rest of the lookup */
681 for (avp = bvp; *pvp != NULL && **bvp != MATCHELOOKUP; bvp++)
682 continue;
683 if (*bvp == NULL)
684 return (pvp);
685 p = *bvp;
686 *bvp = NULL;
687 cataddr(avp, buf2, sizeof buf2);
688 *bvp++ = p;
689
690 /* save the part after the lookup */
691 cataddr(bvp, buf3, sizeof buf3);
692
693 /*
694 ** Now look up the middle part.
695 */
696
697 p = aliaslookup(buf2);
698 if (p != NULL)
699 strcpy(buf2, p);
700
701 /*
702 ** Put the three parts back together and break into tokens.
703 */
704
705 strcat(buf1, buf2);
706 strcat(buf1, buf3);
707 avp = prescan(buf1, '\0');
708
709 /* return this mapping */
710 return (avp);
711}