delete $<
[unix-history] / usr / src / usr.sbin / sendmail / src / alias.c
CommitLineData
d185cb11 1/*
1f7bda54 2 * Copyright (c) 1983 Eric P. Allman
bee79b64
KB
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
417f7a11 6 * %sccs.include.redist.c%
bee79b64
KB
7 */
8
72041f93 9# include "sendmail.h"
ce8f0b62 10# include <sys/stat.h>
2e2e5270 11# include <sys/file.h>
ce8f0b62 12# include <signal.h>
76b607b2 13# include <fcntl.h>
f9344236 14# include <pwd.h>
ce8f0b62 15
4099e6e8 16# ifdef DBM
33fc5854 17ERROR: DBM is no longer supported -- use NDBM instead.
4099e6e8
EA
18# endif
19
ce8f0b62
EA
20# ifdef NEWDB
21# include <db.h>
22# endif
23
6a2bb17b 24# ifdef NDBM
4099e6e8 25# include <ndbm.h>
6a2bb17b
EA
26# endif
27
bee79b64 28#ifndef lint
b9357db9 29#ifdef NEWDB
6feb509e 30#ifdef NDBM
dd3ec3f5 31static char sccsid[] = "@(#)alias.c 6.24 (Berkeley) %G% (with NEWDB and NDBM)";
6feb509e 32#else
dd3ec3f5 33static char sccsid[] = "@(#)alias.c 6.24 (Berkeley) %G% (with NEWDB)";
6feb509e 34#endif
07c0651f 35#else
4099e6e8 36#ifdef NDBM
dd3ec3f5 37static char sccsid[] = "@(#)alias.c 6.24 (Berkeley) %G% (with NDBM)";
b9357db9 38#else
dd3ec3f5 39static char sccsid[] = "@(#)alias.c 6.24 (Berkeley) %G% (without NEWDB or NDBM)";
b9357db9 40#endif
bee79b64
KB
41#endif
42#endif /* not lint */
07c0651f 43\f/*
b3cbe40f
EA
44** ALIAS -- Compute aliases.
45**
7338e3d4
EA
46** Scans the alias file for an alias for the given address.
47** If found, it arranges to deliver to the alias list instead.
48** Uses libdbm database if -DDBM.
b3cbe40f
EA
49**
50** Parameters:
bdfaa762 51** a -- address to alias.
d4f42161
EA
52** sendq -- a pointer to the head of the send queue
53** to put the aliases in.
8f48def8 54** e -- the current envelope.
b3cbe40f
EA
55**
56** Returns:
57** none
58**
59** Side Effects:
9e3c0a28 60** Aliases found are expanded.
b3cbe40f 61**
b3cbe40f
EA
62** Notes:
63** If NoAlias (the "-n" flag) is set, no aliasing is
64** done.
65**
66** Deficiencies:
67** It should complain about names that are aliased to
68** nothing.
b3cbe40f
EA
69*/
70
71
6c6e2d3a
EA
72/*
73** Sun YP servers read the dbm files directly, so we have to build them
74** even if NEWDB
75*/
76
4099e6e8 77#ifdef NDBM
6c6e2d3a
EA
78# ifndef NEWDB
79# define IF_MAKEDBMFILES
80# else
81# ifdef YPCOMPAT
82# define IF_MAKEDBMFILES if (makedbmfiles)
83# endif
84# endif
85#endif
86
4099e6e8 87typedef union
a530c75f 88{
4099e6e8
EA
89#ifdef NDBM
90 datum dbm;
07c0651f 91#endif
4099e6e8
EA
92#ifdef NEWDB
93 DBT dbt;
94#endif
95 struct
96 {
97 char *data;
98 int size;
99 } xx;
100} DBdatum;
b9357db9
EA
101
102#ifdef NEWDB
103static DB *AliasDBptr;
104#endif
4099e6e8
EA
105#ifdef NDBM
106static DBM *AliasDBMptr;
107#endif
b3cbe40f 108
a4076aed 109alias(a, sendq, e)
bdfaa762 110 register ADDRESS *a;
d4f42161 111 ADDRESS **sendq;
a4076aed 112 register ENVELOPE *e;
b3cbe40f 113{
29871fef 114 register char *p;
1c7897ef 115 int naliases;
84daea29
EA
116 char *owner;
117 char obuf[MAXNAME + 6];
abae7b2d 118 extern ADDRESS *sendto();
35cc3fad 119 extern char *aliaslookup();
b3cbe40f 120
9678c96d 121 if (tTd(27, 1))
cdb17311 122 printf("alias(%s)\n", a->q_paddr);
b3cbe40f 123
cdb17311 124 /* don't realias already aliased names */
8bcce465 125 if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
cdb17311
EA
126 return;
127
a4076aed 128 e->e_to = a->q_paddr;
cdb17311 129
74c5fe7c
EA
130 /*
131 ** Look up this name
132 */
133
2e3062fe
EA
134 if (NoAlias)
135 p = NULL;
136 else
137 p = aliaslookup(a->q_user);
cdb17311
EA
138 if (p == NULL)
139 return;
b3cbe40f 140
d916f0ca 141 /*
cdb17311
EA
142 ** Match on Alias.
143 ** Deliver to the target list.
d916f0ca
EA
144 */
145
9678c96d 146 if (tTd(27, 1))
cdb17311
EA
147 printf("%s (%s, %s) aliased to %s\n",
148 a->q_paddr, a->q_host, a->q_user, p);
8f48def8 149 if (bitset(EF_VRFYONLY, e->e_flags))
8bcce465
EA
150 {
151 a->q_flags |= QVERIFIED;
8f48def8 152 return;
8bcce465
EA
153 }
154 message("aliased to %s", p);
aa102c71 155#ifdef LOG
68f7099c 156 if (LogLevel > 9)
aa102c71
EA
157 syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
158#endif
1c7897ef 159 a->q_flags &= ~QSELFREF;
cdb17311 160 AliasLevel++;
abae7b2d 161 a->q_child = sendto(p, 1, a, 0);
cdb17311 162 AliasLevel--;
1c7897ef 163 if (naliases > 0 && !bitset(QSELFREF, a->q_flags))
f7eca811
EA
164 {
165 if (tTd(27, 5))
166 {
167 printf("alias: QDONTSEND ");
168 printaddr(a, FALSE);
169 }
170 a->q_flags |= QDONTSEND;
171 }
84daea29
EA
172
173 /*
174 ** Look for owner of alias
175 */
176
177 (void) strcpy(obuf, "owner-");
178 if (strncmp(a->q_user, "owner-", 6) == 0)
179 (void) strcat(obuf, "owner");
180 else
181 (void) strcat(obuf, a->q_user);
182 if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
183 makelower(obuf);
184 owner = aliaslookup(obuf);
185 if (owner != NULL)
186 {
187 if (strchr(owner, ',') != NULL)
188 owner = obuf;
189 a->q_owner = newstr(owner);
190 }
cdb17311
EA
191}
192\f/*
35cc3fad
EA
193** ALIASLOOKUP -- look up a name in the alias file.
194**
195** Parameters:
196** name -- the name to look up.
197**
198** Returns:
199** the value of name.
200** NULL if unknown.
201**
202** Side Effects:
203** none.
204**
205** Warnings:
206** The return value will be trashed across calls.
207*/
208
209char *
210aliaslookup(name)
211 char *name;
212{
698a71d9
EA
213 int i;
214 char keybuf[MAXNAME + 1];
4099e6e8
EA
215# if defined(NEWDB) || defined(NDBM)
216 DBdatum rhs, lhs;
b9357db9 217 int s;
698a71d9
EA
218# else /* neither NEWDB nor NDBM */
219 register STAB *s;
220# endif
35cc3fad
EA
221
222 /* create a key for fetch */
698a71d9
EA
223 i = strlen(name) + 1;
224 if (i > sizeof keybuf)
225 i = sizeof keybuf;
226 bcopy(name, keybuf, i);
227 if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
228 makelower(keybuf);
229
230# if defined(NEWDB) || defined(NDBM)
231 lhs.xx.size = i;
232 lhs.xx.data = keybuf;
b9357db9 233# ifdef NEWDB
07c0651f
EA
234 if (AliasDBptr != NULL)
235 {
698a71d9
EA
236 i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
237 if (i == 0)
4099e6e8 238 return (rhs.dbt.data);
07c0651f 239 }
4099e6e8 240# ifdef NDBM
c796f255 241 else if (AliasDBMptr != NULL)
07c0651f 242 {
4099e6e8
EA
243 rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
244 return (rhs.dbm.dptr);
07c0651f 245 }
4099e6e8 246# endif /* NDBM */
5039bcf5 247 return (NULL);
4099e6e8
EA
248# else /* not NEWDB */
249 rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
250 return (rhs.dbm.dptr);
251# endif /* NEWDB */
252# else /* neither NEWDB nor NDBM */
698a71d9 253 s = stab(keybuf, ST_ALIAS, ST_FIND);
07c0651f
EA
254 if (s != NULL)
255 return (s->s_alias);
07c0651f 256 return (NULL);
5039bcf5 257# endif
35cc3fad
EA
258}
259\f/*
cdb17311
EA
260** INITALIASES -- initialize for aliasing
261**
4099e6e8 262** Very different depending on whether we are running NDBM or not.
cdb17311
EA
263**
264** Parameters:
265** aliasfile -- location of aliases.
4099e6e8 266** init -- if set and if NDBM, initialize the NDBM files.
cdb17311
EA
267**
268** Returns:
269** none.
270**
271** Side Effects:
272** initializes aliases:
4099e6e8
EA
273** if NDBM: opens the database.
274** if ~NDBM: reads the aliases into the symbol table.
cdb17311
EA
275*/
276
915f268d 277# define DBMMODE 0644
f4dbf345 278
a4076aed 279initaliases(aliasfile, init, e)
cdb17311 280 char *aliasfile;
f4dbf345 281 bool init;
a4076aed 282 register ENVELOPE *e;
cdb17311 283{
4099e6e8 284#if defined(NDBM) || defined(NEWDB)
7bdc419c 285 int atcnt;
d6b27179 286 time_t modtime;
9327783c
EA
287 bool automatic = FALSE;
288 char buf[MAXNAME];
b9357db9 289#endif
7338e3d4 290 struct stat stb;
a78155b0 291 static bool initialized = FALSE;
0df908a9 292 static int readaliases();
a78155b0
EA
293
294 if (initialized)
295 return;
296 initialized = TRUE;
d6b27179 297
bb09c502 298 if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
7bdc419c 299 {
9327783c 300 if (aliasfile != NULL && init)
b6edea3d 301 syserr("554 Cannot open %s", aliasfile);
7bdc419c 302 NoAlias = TRUE;
70faa7c8 303 errno = 0;
7bdc419c
EA
304 return;
305 }
306
4099e6e8 307# if defined(NDBM) || defined(NEWDB)
7bdc419c
EA
308 /*
309 ** Check to see that the alias file is complete.
310 ** If not, we will assume that someone died, and it is up
311 ** to us to rebuild it.
312 */
313
a1a07282 314 if (!init)
b9357db9
EA
315 {
316# ifdef NEWDB
317 (void) strcpy(buf, aliasfile);
318 (void) strcat(buf, ".db");
15af6d40 319 AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
aace356e
EA
320 if (AliasDBptr == NULL)
321 {
4099e6e8
EA
322# ifdef NDBM
323 AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
c796f255
EA
324 if (AliasDBMptr == NULL)
325 {
326 syserr("initaliases: cannot open %s", buf);
327 NoAlias = TRUE;
328 return;
329 }
07c0651f 330# else
aace356e
EA
331 syserr("initaliases: cannot open %s", buf);
332 NoAlias = TRUE;
333 return;
07c0651f 334# endif
aace356e 335 }
b9357db9 336# else
4099e6e8 337 AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
c796f255
EA
338 if (AliasDBMptr == NULL)
339 {
aa102c71
EA
340 syserr("initaliases: cannot open DBM database %s.{pag,dir}",
341 aliasfile);
c796f255
EA
342 NoAlias = TRUE;
343 return;
344 }
b9357db9
EA
345# endif
346 }
560a80d9
EA
347 atcnt = SafeAlias * 2;
348 if (atcnt > 0)
349 {
350 while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
a1a07282
EA
351 {
352 /*
353 ** Reinitialize alias file in case the new
354 ** one is mv'ed in instead of cp'ed in.
355 **
356 ** Only works with new DBM -- old one will
357 ** just consume file descriptors forever.
358 ** If you have a dbmclose() it can be
359 ** added before the sleep(30).
360 */
361
b9357db9 362# ifdef NEWDB
07c0651f
EA
363 if (AliasDBptr != NULL)
364 AliasDBptr->close(AliasDBptr);
b9357db9 365# endif
4099e6e8
EA
366# ifdef NDBM
367 if (AliasDBMptr != NULL)
368 dbm_close(AliasDBMptr);
369# endif
b9357db9 370
560a80d9 371 sleep(30);
b9357db9
EA
372# ifdef NEWDB
373 (void) strcpy(buf, aliasfile);
374 (void) strcat(buf, ".db");
15af6d40
KB
375 AliasDBptr =
376 dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
aace356e
EA
377 if (AliasDBptr == NULL)
378 {
07c0651f 379# ifdef NDBM
4099e6e8 380 AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
07c0651f 381# else
aace356e
EA
382 syserr("initaliases: cannot open %s", buf);
383 NoAlias = TRUE;
384 return;
07c0651f 385# endif
aace356e 386 }
b9357db9 387# else
a1a07282 388# ifdef NDBM
4099e6e8 389 AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
c796f255
EA
390 if (AliasDBMptr == NULL)
391 {
51d9cc47
EA
392 syserr("initaliases: cannot open DBM database %s.{pag,dir}",
393 aliasfile);
c796f255
EA
394 NoAlias = TRUE;
395 return;
396 }
b9357db9
EA
397# endif
398# endif
a1a07282 399 }
560a80d9
EA
400 }
401 else
402 atcnt = 1;
7bdc419c 403
d6b27179 404 /*
4099e6e8 405 ** See if the NDBM version of the file is out of date with
d6b27179 406 ** the text version. If so, go into 'init' mode automatically.
915f268d
KB
407 ** This only happens if our effective userid owns the DBM.
408 ** Note the unpalatable hack to see if the stat succeeded.
d6b27179
EA
409 */
410
d6b27179
EA
411 modtime = stb.st_mtime;
412 (void) strcpy(buf, aliasfile);
b9357db9
EA
413# ifdef NEWDB
414 (void) strcat(buf, ".db");
415# else
d6b27179 416 (void) strcat(buf, ".pag");
b9357db9 417# endif
d6b27179 418 stb.st_ino = 0;
f12e5a74 419 if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
f4dbf345 420 {
70faa7c8 421 errno = 0;
915f268d 422 if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
d6b27179
EA
423 {
424 init = TRUE;
9327783c 425 automatic = TRUE;
b6edea3d 426 message("rebuilding alias database");
2e3062fe 427#ifdef LOG
68f7099c 428 if (LogLevel > 14)
2e3062fe 429 syslog(LOG_INFO, "rebuilding alias database");
f3d8f6d6 430#endif /* LOG */
d6b27179
EA
431 }
432 else
433 {
f12e5a74 434#ifdef LOG
68f7099c 435 if (LogLevel > 3)
2e3062fe 436 syslog(LOG_INFO, "alias database out of date");
f3d8f6d6 437#endif /* LOG */
b6edea3d 438 message("Warning: alias database out of date");
d6b27179
EA
439 }
440 }
f4dbf345 441
d6b27179
EA
442
443 /*
4099e6e8
EA
444 ** If necessary, load the NDBM file.
445 ** If running without NDBM, load the symbol table.
d6b27179
EA
446 */
447
f4dbf345 448 if (init)
7bdc419c 449 {
9327783c 450#ifdef LOG
68f7099c 451 if (LogLevel > 7)
9327783c
EA
452 {
453 extern char *username();
454
455 syslog(LOG_NOTICE, "alias database %srebuilt by %s",
456 automatic ? "auto" : "", username());
457 }
f3d8f6d6 458#endif /* LOG */
a4076aed 459 readaliases(aliasfile, TRUE, e);
7bdc419c 460 }
4099e6e8 461# else /* NDBM */
a4076aed 462 readaliases(aliasfile, init, e);
4099e6e8 463# endif /* NDBM */
f4dbf345
EA
464}
465\f/*
466** READALIASES -- read and process the alias file.
467**
468** This routine implements the part of initaliases that occurs
469** when we are not going to use the DBM stuff.
470**
471** Parameters:
472** aliasfile -- the pathname of the alias file master.
4099e6e8 473** init -- if set, initialize the NDBM stuff.
f4dbf345
EA
474**
475** Returns:
476** none.
477**
478** Side Effects:
479** Reads aliasfile into the symbol table.
480** Optionally, builds the .dir & .pag files.
481*/
482
483static
a4076aed 484readaliases(aliasfile, init, e)
f4dbf345
EA
485 char *aliasfile;
486 bool init;
a4076aed 487 register ENVELOPE *e;
f4dbf345 488{
cdb17311 489 register char *p;
41173b8f 490 char *lhs;
cdb17311
EA
491 char *rhs;
492 bool skipping;
7338e3d4 493 int naliases, bytes, longest;
9e25d1f0 494 FILE *af;
6c6e2d3a 495 bool makedbmfiles;
21c8ba49 496 void (*oldsigint)();
7338e3d4 497 ADDRESS al, bl;
9e25d1f0 498 register STAB *s;
b9357db9
EA
499# ifdef NEWDB
500 DB *dbp;
76b607b2 501# endif
4099e6e8
EA
502# ifdef NDBM
503 DBM *dbmp;
504# endif
76b607b2
EA
505# ifdef LOCKF
506 struct flock fld;
b9357db9 507# endif
7338e3d4 508 char line[BUFSIZ];
cdb17311 509
76b607b2 510 if ((af = fopen(aliasfile, "r+")) == NULL)
d916f0ca 511 {
c796f255 512 if (init)
b6edea3d 513 syserr("554 Can't open %s", aliasfile);
c796f255 514 else if (tTd(27, 1))
9e25d1f0 515 printf("Can't open %s\n", aliasfile);
cdb17311
EA
516 errno = 0;
517 NoAlias++;
518 return;
519 }
74c5fe7c 520
4099e6e8 521# if defined(NDBM) || defined(NEWDB)
e6e345fa 522 /* see if someone else is rebuilding the alias file already */
4287d84d 523# ifdef LOCKF
76b607b2
EA
524 fld.l_type = F_WRLCK;
525 fld.l_whence = fld.l_start = fld.l_len = 0;
526 if (fcntl(fileno(af), F_SETLK, &fld) < 0)
4287d84d 527# else
e6e345fa 528 if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
4287d84d 529# endif
e6e345fa
EA
530 {
531 /* yes, they are -- wait until done and then return */
b6edea3d 532 message("Alias file is already being rebuilt");
e6e345fa
EA
533 if (OpMode != MD_INITALIAS)
534 {
535 /* wait for other rebuild to complete */
4287d84d 536# ifdef LOCKF
76b607b2 537 (void) fcntl(fileno(af), F_SETLKW, &fld);
4287d84d 538# else
e6e345fa 539 (void) flock(fileno(af), LOCK_EX);
4287d84d 540# endif
e6e345fa 541 }
03388044 542 (void) fclose(af);
e6e345fa
EA
543 errno = 0;
544 return;
545 }
4099e6e8 546# endif /* NDBM */
e6e345fa
EA
547
548 /*
549 ** If initializing, create the new DBM files.
550 */
551
552 if (init)
553 {
554 oldsigint = signal(SIGINT, SIG_IGN);
07c0651f
EA
555# ifdef NEWDB
556 (void) strcpy(line, aliasfile);
557 (void) strcat(line, ".db");
558 dbp = dbopen(line,
559 O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
560 if (dbp == NULL)
561 {
562 syserr("readaliases: cannot create %s", line);
563 (void) signal(SIGINT, oldsigint);
564 return;
565 }
6c6e2d3a
EA
566# endif
567# ifdef IF_MAKEDBMFILES
568# ifdef NEWDB
569 makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
570# endif
571 IF_MAKEDBMFILES
e6e345fa 572 {
4099e6e8
EA
573 dbmp = dbm_open(aliasfile,
574 O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
575 if (dbmp == NULL)
6c6e2d3a 576 {
4099e6e8
EA
577 syserr("readaliases: cannot create %s.{dir,pag}",
578 aliasfile);
6c6e2d3a
EA
579 (void) signal(SIGINT, oldsigint);
580 return;
581 }
e6e345fa 582 }
b9357db9 583# endif
e6e345fa
EA
584 }
585
74c5fe7c
EA
586 /*
587 ** Read and interpret lines
588 */
589
7338e3d4
EA
590 FileName = aliasfile;
591 LineNumber = 0;
d6b27179 592 naliases = bytes = longest = 0;
cdb17311
EA
593 skipping = FALSE;
594 while (fgets(line, sizeof (line), af) != NULL)
595 {
d6b27179
EA
596 int lhssize, rhssize;
597
7338e3d4 598 LineNumber++;
f3d8f6d6 599 p = strchr(line, '\n');
3312f93c
EA
600 if (p != NULL)
601 *p = '\0';
cdb17311
EA
602 switch (line[0])
603 {
604 case '#':
cdb17311
EA
605 case '\0':
606 skipping = FALSE;
607 continue;
bdfaa762 608
cdb17311
EA
609 case ' ':
610 case '\t':
611 if (!skipping)
b6edea3d 612 syserr("554 Non-continuation line starts with space");
cdb17311 613 skipping = TRUE;
bdfaa762 614 continue;
cdb17311
EA
615 }
616 skipping = FALSE;
bdfaa762 617
74c5fe7c
EA
618 /*
619 ** Process the LHS
41173b8f 620 **
6feb509e 621 ** Find the colon separator, and parse the address.
41173b8f
EA
622 ** It should resolve to a local name.
623 **
624 ** Alternatively, it can be "@hostname" for host
625 ** aliases -- all we do here is map case. Hostname
626 ** need not be a single token.
74c5fe7c
EA
627 */
628
cdb17311 629 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
bdfaa762 630 continue;
41173b8f 631 if (*p != ':')
cdb17311 632 {
1bcdf0a2 633 syserr("%s, line %d: syntax error", aliasfile, lineno);
bdfaa762 634 continue;
cdb17311 635 }
41173b8f
EA
636 *p++ = '\0';
637 if (line[0] == '@')
cdb17311 638 {
41173b8f
EA
639 /* a host alias */
640 makelower(line);
641 lhs = line;
642 }
643 else
644 {
645 /* a user alias */
646 if (parseaddr(line, &al, 1, ':') == NULL)
647 {
648 syserr("illegal alias name");
649 continue;
650 }
651 loweraddr(&al);
652 if (al.q_mailer != LocalMailer)
653 {
654 syserr("cannot alias non-local names");
655 continue;
656 }
657 lhs = al.q_user;
cdb17311 658 }
74c5fe7c
EA
659
660 /*
661 ** Process the RHS.
662 ** 'al' is the internal form of the LHS address.
663 ** 'p' points to the text of the RHS.
1bcdf0a2
EA
664 ** 'p' may begin with a colon (i.e., the
665 ** separator was "::") which will use the
666 ** first address as the person to send
667 ** errors to -- i.e., designates the
668 ** list maintainer.
74c5fe7c
EA
669 */
670
1bcdf0a2
EA
671 if (*p == ':')
672 {
673 ADDRESS *maint;
674
675 while (isspace(*++p))
676 continue;
677 rhs = p;
678 while (*p != '\0' && *p != ',')
679 p++;
680 if (*p != ',')
681 goto syntaxerr;
682 *p++ = '\0';
683 maint = parse(p, (ADDRESS *) NULL, 1);
684 if (maint == NULL)
685 syserr("Illegal list maintainer for list %s", al.q_user);
686 else if (CurEnv->e_returnto == &CurEnv->e_from)
687 {
688 CurEnv->e_returnto = maint;
689 MailBack++;
690 }
691 }
692
cdb17311 693 rhs = p;
cdb17311
EA
694 for (;;)
695 {
696 register char c;
0957ee6f
EA
697 register char *nlp;
698
699 nlp = &p[strlen(p)];
700 if (nlp[-1] == '\n')
701 *--nlp = '\0';
d916f0ca 702
1e963db5 703 if (init && CheckAliases)
cdb17311 704 {
f4dbf345 705 /* do parsing & compression of addresses */
3312f93c 706 while (*p != '\0')
cdb17311 707 {
9e2cf26f 708 auto char *delimptr;
3312f93c 709
2bee003d
EA
710 while ((isascii(*p) && isspace(*p)) ||
711 *p == ',')
c49d661c 712 p++;
3312f93c
EA
713 if (*p == '\0')
714 break;
9e2cf26f 715 if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL)
b6edea3d 716 usrerr("553 %s... bad address", p);
9e2cf26f 717 p = delimptr;
cdb17311 718 }
cdb17311 719 }
f4dbf345 720 else
634c8ff3 721 {
0957ee6f 722 p = nlp;
634c8ff3 723 }
d916f0ca 724
cdb17311 725 /* see if there should be a continuation line */
9e25d1f0
EA
726 c = fgetc(af);
727 if (!feof(af))
74c5fe7c 728 (void) ungetc(c, af);
9e25d1f0 729 if (c != ' ' && c != '\t')
cdb17311
EA
730 break;
731
732 /* read continuation line */
cdb17311
EA
733 if (fgets(p, sizeof line - (p - line), af) == NULL)
734 break;
7338e3d4 735 LineNumber++;
07b49560
EA
736
737 /* check for line overflow */
738 if (strchr(p, '\n') == NULL)
739 {
b6edea3d 740 usrerr("554 alias too long");
07b49560
EA
741 break;
742 }
cdb17311 743 }
74c5fe7c
EA
744
745 /*
746 ** Insert alias into symbol table or DBM file
747 */
748
41173b8f 749 lhssize = strlen(lhs) + 1;
d6b27179
EA
750 rhssize = strlen(rhs) + 1;
751
4099e6e8 752# if defined(NDBM) || defined(NEWDB)
f4dbf345
EA
753 if (init)
754 {
4099e6e8 755 DBdatum key, content;
698a71d9 756 int putstat;
f4dbf345 757
4099e6e8
EA
758 key.xx.size = lhssize;
759 key.xx.data = al.q_user;
760 content.xx.size = rhssize;
761 content.xx.data = rhs;
07c0651f 762# ifdef NEWDB
698a71d9
EA
763 putstat = dbp->put(dbp, &key.dbt, &content.dbt,
764 R_NOOVERWRITE);
765 if (putstat > 0)
766 {
aa102c71 767 usrerr("050 Warning: duplicate alias name %s",
698a71d9
EA
768 al.q_user);
769 putstat = dbp->put(dbp, &key.dbt,
770 &content.dbt, 0);
771 }
772 if (putstat != 0)
aace356e 773 syserr("readaliases: db put (%s)", al.q_user);
6c6e2d3a
EA
774# endif
775# ifdef IF_MAKEDBMFILES
776 IF_MAKEDBMFILES
698a71d9
EA
777 {
778 putstat = dbm_store(dbmp, key.dbm, content.dbm,
779 DBM_INSERT);
780 if (putstat > 0)
781 {
aa102c71 782 usrerr("050 Warning: duplicate alias name %s",
698a71d9
EA
783 al.q_user);
784 putstat = dbm_store(dbmp, key.dbm,
785 content.dbm, DBM_REPLACE);
786 }
787 if (putstat != 0)
4099e6e8
EA
788 syserr("readaliases: dbm store (%s)",
789 al.q_user);
698a71d9 790 }
b9357db9 791# endif
698a71d9
EA
792 if (al.q_paddr != NULL)
793 free(al.q_paddr);
794 if (al.q_host != NULL)
795 free(al.q_host);
796 if (al.q_user != NULL)
797 free(al.q_user);
f4dbf345
EA
798 }
799 else
4099e6e8 800# endif /* NDBM */
f4dbf345
EA
801 {
802 s = stab(al.q_user, ST_ALIAS, ST_ENTER);
803 s->s_alias = newstr(rhs);
804 }
d6b27179
EA
805
806 /* statistics */
807 naliases++;
808 bytes += lhssize + rhssize;
809 if (rhssize > longest)
810 longest = rhssize;
d916f0ca 811 }
e6e345fa 812
4099e6e8 813# if defined(NDBM) || defined(NEWDB)
e6e345fa
EA
814 if (init)
815 {
816 /* add the distinquished alias "@" */
4099e6e8 817 DBdatum key;
b9357db9 818
4099e6e8
EA
819 key.xx.size = 2;
820 key.xx.data = "@";
b9357db9 821# ifdef NEWDB
aace356e 822 if (dbp->sync(dbp) != 0 ||
4099e6e8 823 dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
aace356e
EA
824 dbp->close(dbp) != 0)
825 syserr("readaliases: db close failure");
6c6e2d3a 826# endif
a47061b6 827# ifdef IF_MAKEDBMFILES
09098a56 828 IF_MAKEDBMFILES
4099e6e8 829 {
c25096f0
EA
830#ifdef YPCOMPAT
831 nis_magic(dbmp);
832#endif
4099e6e8
EA
833 if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
834 dbm_error(dbmp))
835 syserr("readaliases: dbm close failure");
836 dbm_close(dbmp);
837 }
b9357db9 838# endif
e6e345fa
EA
839
840 /* restore the old signal */
841 (void) signal(SIGINT, oldsigint);
842 }
4099e6e8 843# endif /* NDBM */
e6e345fa
EA
844
845 /* closing the alias file drops the lock */
cdb17311 846 (void) fclose(af);
a4076aed 847 e->e_to = NULL;
7338e3d4 848 FileName = NULL;
b6edea3d 849 message("%d aliases, longest %d bytes, %d bytes total",
d6b27179 850 naliases, longest, bytes);
2e3062fe 851# ifdef LOG
68f7099c 852 if (LogLevel > 7)
2e3062fe
EA
853 syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
854 naliases, longest, bytes);
f3d8f6d6 855# endif /* LOG */
b3cbe40f
EA
856}
857\f/*
c25096f0
EA
858** NIS_MAGIC -- Add NIS magic dbm data
859**
860** This adds the magic entries needed by SunOS to make this a valid
861** NIS map.
862**
863** Parameters:
864** dbmp -- a pointer to the DBM structure.
865**
866** Returns:
867** none.
868*/
869
870# ifdef YPCOMPAT
871
872static void
873nis_magic(dbmp)
874 DBM *dbmp;
875{
876 int i;
877 static datum key[2] =
878 {
879 { "YP_LAST_MODIFIED", sizeof "YP_LAST_MODIFIED" - 1 },
880 { "YP_MASTER_NAME", sizeof "YP_MASTER_NAME" - 1 },
881 };
882 datum contents[2];
883 char tbuf[12];
884 char hbuf[MAXHOSTNAMELEN];
885
886 (void) sprintf(tbuf, "%010ld", curtime());
887 contents[0].dptr = tbuf;
888 contents[0].dsize = strlen(tbuf);
889
890 (void) myhostname(hbuf, sizeof hbuf);
891 contents[1].dptr = hbuf;
892 contents[1].dptr = strlen(hbuf);
893
894 for (i = 0; i < sizeof key / sizeof *key; i++)
895 {
896 if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 ||
897 dbm_error(dbmp))
898 syserr("nis_magic: dbm_store failure");
899 }
900}
901
902# endif
903\f/*
b3cbe40f
EA
904** FORWARD -- Try to forward mail
905**
906** This is similar but not identical to aliasing.
907**
b3cbe40f 908** Parameters:
74c5fe7c
EA
909** user -- the name of the user who's mail we would like
910** to forward to. It must have been verified --
911** i.e., the q_home field must have been filled
912** in.
d4f42161
EA
913** sendq -- a pointer to the head of the send queue to
914** put this user's aliases in.
b3cbe40f
EA
915**
916** Returns:
cdb17311 917** none.
b3cbe40f
EA
918**
919** Side Effects:
9e3c0a28 920** New names are added to send queues.
b3cbe40f
EA
921*/
922
a4076aed 923forward(user, sendq, e)
a530c75f 924 ADDRESS *user;
d4f42161 925 ADDRESS **sendq;
a4076aed 926 register ENVELOPE *e;
b3cbe40f 927{
e0136832
EA
928 char *pp;
929 char *ep;
56678245 930
9678c96d 931 if (tTd(27, 1))
cdb17311 932 printf("forward(%s)\n", user->q_paddr);
cdb17311 933
179c1218 934 if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
cdb17311 935 return;
74c5fe7c 936 if (user->q_home == NULL)
c25096f0 937 {
b6edea3d 938 syserr("554 forward: no home");
c25096f0
EA
939 user->q_home = "/nosuchdirectory";
940 }
56678245 941
56678245 942 /* good address -- look for .forward file in home */
a4076aed 943 define('z', user->q_home, e);
e0136832
EA
944 define('u', user->q_user, e);
945 define('h', user->q_host, e);
946 if (ForwardPath == NULL)
2bee003d 947 ForwardPath = newstr("\201z/.forward");
e0136832
EA
948
949 for (pp = ForwardPath; pp != NULL; pp = ep)
950 {
118e6693 951 int err;
f43b04ce 952 char buf[MAXPATHLEN+1];
e0136832
EA
953
954 ep = strchr(pp, ':');
955 if (ep != NULL)
956 *ep = '\0';
957 expand(pp, buf, &buf[sizeof buf - 1], e);
958 if (ep != NULL)
959 *ep++ = ':';
960 if (tTd(27, 3))
961 printf("forward: trying %s\n", buf);
118e6693
EA
962 err = include(buf, TRUE, user, sendq, e);
963 if (err == 0)
e0136832 964 break;
118e6693
EA
965 if (transienterror(err))
966 {
967 /* we have to suspend this message */
968 user->q_flags |= QQUEUEUP|QDONTSEND;
969 return;
970 }
e0136832 971 }
b3cbe40f 972}
41173b8f
EA
973\f/*
974** MAPHOST -- given a host description, produce a mapping.
975**
976** This is done by looking up the name in the alias file,
977** preceeded by an "@". This can be used for UUCP mapping.
978** For example, a call with {blia, ., UUCP} as arguments
979** might return {ucsfcgl, !, blia, ., UUCP} as the result.
980**
981** We first break the input into three parts -- before the
982** lookup, the lookup itself, and after the lookup. We
983** then do the lookup, concatenate them together, and rescan
984** the result.
985**
986** Parameters:
987** pvp -- the parameter vector to map.
988**
989** Returns:
990** The result of the mapping. If nothing found, it
991** should just concatenate the three parts together and
992** return that.
993**
994** Side Effects:
995** none.
996*/
997
998char **
999maphost(pvp)
1000 char **pvp;
1001{
1002 register char **avp;
1003 register char **bvp;
1004 char *p;
1005 char buf1[MAXNAME];
1006 char buf2[MAXNAME];
1007 char buf3[MAXNAME];
1008 extern char **prescan();
1009
1010 /*
1011 ** Extract the three parts of the input as strings.
1012 */
1013
1014 /* find the part before the lookup */
1015 for (bvp = pvp; *bvp != NULL && **bvp != MATCHLOOKUP; bvp++)
1016 continue;
1017 if (*bvp == NULL)
1018 return (pvp);
1019 p = *bvp;
1020 *bvp = NULL;
1021 cataddr(pvp, buf1, sizeof buf1);
1022 *bvp++ = p;
1023
1024 /* find the rest of the lookup */
1025 for (avp = bvp; *pvp != NULL && **bvp != MATCHELOOKUP; bvp++)
1026 continue;
1027 if (*bvp == NULL)
1028 return (pvp);
1029 p = *bvp;
1030 *bvp = NULL;
1031 cataddr(avp, buf2, sizeof buf2);
1032 *bvp++ = p;
1033
1034 /* save the part after the lookup */
1035 cataddr(bvp, buf3, sizeof buf3);
1036
1037 /*
1038 ** Now look up the middle part.
1039 */
1040
1041 p = aliaslookup(buf2);
1042 if (p != NULL)
1043 strcpy(buf2, p);
1044
1045 /*
1046 ** Put the three parts back together and break into tokens.
1047 */
1048
1049 strcat(buf1, buf2);
1050 strcat(buf1, buf3);
1051 avp = prescan(buf1, '\0');
1052
1053 /* return this mapping */
1054 return (avp);
1055}