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: 
  11: # include <pwd.h>
  12: # include <sys/types.h>
  13: # include <sys/stat.h>
  14: # include <signal.h>
  15: # include <errno.h>
  16: # include "sendmail.h"
  17: # ifdef FLOCK
  18: # include <sys/file.h>
  19: # endif FLOCK
  20: 
  21: #if !defined(lint) && !defined(NOSCCS)
  22: # ifdef DBM
  23: static char SccsId[] = "@(#)alias.c	5.13 (Berkeley) 4/17/86	(with DBM)";
  24: # else DBM
  25: static char SccsId[] = "@(#)alias.c	5.13 (Berkeley) 4/17/86	(without DBM)";
  26: # endif DBM
  27: #endif
  28: 
  29: 
  30: /*
  31: **  ALIAS -- Compute aliases.
  32: **
  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.
  36: **
  37: **	Parameters:
  38: **		a -- address to alias.
  39: **		sendq -- a pointer to the head of the send queue
  40: **			to put the aliases in.
  41: **
  42: **	Returns:
  43: **		none
  44: **
  45: **	Side Effects:
  46: **		Aliases found are expanded.
  47: **
  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.
  55: */
  56: 
  57: 
  58: #ifdef DBM
  59: typedef struct
  60: {
  61:     char    *dptr;
  62:     int dsize;
  63: } DATUM;
  64: extern DATUM fetch();
  65: #endif DBM
  66: 
  67: alias(a, sendq)
  68:     register ADDRESS *a;
  69:     ADDRESS **sendq;
  70: {
  71:     register char *p;
  72:     extern char *aliaslookup();
  73: 
  74: # ifdef DEBUG
  75:     if (tTd(27, 1))
  76:         printf("alias(%s)\n", a->q_paddr);
  77: # endif
  78: 
  79:     /* don't realias already aliased names */
  80:     if (bitset(QDONTSEND, a->q_flags))
  81:         return;
  82: 
  83:     CurEnv->e_to = a->q_paddr;
  84: 
  85:     /*
  86: 	**  Look up this name
  87: 	*/
  88: 
  89:     if (NoAlias)
  90:         p = NULL;
  91:     else
  92:         p = aliaslookup(a->q_user);
  93:     if (p == NULL)
  94:         return;
  95: 
  96:     /*
  97: 	**  Match on Alias.
  98: 	**	Deliver to the target list.
  99: 	*/
 100: 
 101: # ifdef DEBUG
 102:     if (tTd(27, 1))
 103:         printf("%s (%s, %s) aliased to %s\n",
 104:             a->q_paddr, a->q_host, a->q_user, p);
 105: # endif
 106:     message(Arpa_Info, "aliased to %s", p);
 107:     AliasLevel++;
 108:     sendtolist(p, a, sendq);
 109:     AliasLevel--;
 110: }
 111: /*
 112: **  ALIASLOOKUP -- look up a name in the alias file.
 113: **
 114: **	Parameters:
 115: **		name -- the name to look up.
 116: **
 117: **	Returns:
 118: **		the value of name.
 119: **		NULL if unknown.
 120: **
 121: **	Side Effects:
 122: **		none.
 123: **
 124: **	Warnings:
 125: **		The return value will be trashed across calls.
 126: */
 127: 
 128: char *
 129: aliaslookup(name)
 130:     char *name;
 131: {
 132: # ifdef DBM
 133:     DATUM rhs, lhs;
 134: 
 135:     /* create a key for fetch */
 136:     lhs.dptr = name;
 137:     lhs.dsize = strlen(name) + 1;
 138:     rhs = fetch(lhs);
 139:     return (rhs.dptr);
 140: # else DBM
 141:     register STAB *s;
 142: 
 143:     s = stab(name, ST_ALIAS, ST_FIND);
 144:     if (s == NULL)
 145:         return (NULL);
 146:     return (s->s_alias);
 147: # endif DBM
 148: }
 149: /*
 150: **  INITALIASES -- initialize for aliasing
 151: **
 152: **	Very different depending on whether we are running DBM or not.
 153: **
 154: **	Parameters:
 155: **		aliasfile -- location of aliases.
 156: **		init -- if set and if DBM, initialize the DBM files.
 157: **
 158: **	Returns:
 159: **		none.
 160: **
 161: **	Side Effects:
 162: **		initializes aliases:
 163: **		if DBM:  opens the database.
 164: **		if ~DBM: reads the aliases into the symbol table.
 165: */
 166: 
 167: # define DBMMODE    0644
 168: 
 169: initaliases(aliasfile, init)
 170:     char *aliasfile;
 171:     bool init;
 172: {
 173: #ifdef DBM
 174:     int atcnt;
 175:     time_t modtime;
 176:     bool automatic = FALSE;
 177:     char buf[MAXNAME];
 178: #endif DBM
 179:     struct stat stb;
 180:     static bool initialized = FALSE;
 181: 
 182:     if (initialized)
 183:         return;
 184:     initialized = TRUE;
 185: 
 186:     if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
 187:     {
 188:         if (aliasfile != NULL && init)
 189:             syserr("Cannot open %s", aliasfile);
 190:         NoAlias = TRUE;
 191:         errno = 0;
 192:         return;
 193:     }
 194: 
 195: # ifdef DBM
 196:     /*
 197: 	**  Check to see that the alias file is complete.
 198: 	**	If not, we will assume that someone died, and it is up
 199: 	**	to us to rebuild it.
 200: 	*/
 201: 
 202:     if (!init)
 203:         dbminit(aliasfile);
 204:     atcnt = SafeAlias * 2;
 205:     if (atcnt > 0)
 206:     {
 207:         while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
 208:         {
 209:             /*
 210: 			**  Reinitialize alias file in case the new
 211: 			**  one is mv'ed in instead of cp'ed in.
 212: 			**
 213: 			**	Only works with new DBM -- old one will
 214: 			**	just consume file descriptors forever.
 215: 			**	If you have a dbmclose() it can be
 216: 			**	added before the sleep(30).
 217: 			*/
 218: 
 219:             sleep(30);
 220: # ifdef NDBM
 221:             dbminit(aliasfile);
 222: # endif NDBM
 223:         }
 224:     }
 225:     else
 226:         atcnt = 1;
 227: 
 228:     /*
 229: 	**  See if the DBM version of the file is out of date with
 230: 	**  the text version.  If so, go into 'init' mode automatically.
 231: 	**	This only happens if our effective userid owns the DBM
 232: 	**	version or if the mode of the database is 666 -- this
 233: 	**	is an attempt to avoid protection problems.  Note the
 234: 	**	unpalatable hack to see if the stat succeeded.
 235: 	*/
 236: 
 237:     modtime = stb.st_mtime;
 238:     (void) strcpy(buf, aliasfile);
 239:     (void) strcat(buf, ".pag");
 240:     stb.st_ino = 0;
 241:     if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
 242:     {
 243:         errno = 0;
 244:         if (AutoRebuild && stb.st_ino != 0 &&
 245:             ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid()))
 246:         {
 247:             init = TRUE;
 248:             automatic = TRUE;
 249:             message(Arpa_Info, "rebuilding alias database");
 250: #ifdef LOG
 251:             if (LogLevel >= 7)
 252:                 syslog(LOG_INFO, "rebuilding alias database");
 253: #endif LOG
 254:         }
 255:         else
 256:         {
 257: #ifdef LOG
 258:             if (LogLevel >= 7)
 259:                 syslog(LOG_INFO, "alias database out of date");
 260: #endif LOG
 261:             message(Arpa_Info, "Warning: alias database out of date");
 262:         }
 263:     }
 264: 
 265: 
 266:     /*
 267: 	**  If necessary, load the DBM file.
 268: 	**	If running without DBM, load the symbol table.
 269: 	*/
 270: 
 271:     if (init)
 272:     {
 273: #ifdef LOG
 274:         if (LogLevel >= 6)
 275:         {
 276:             extern char *username();
 277: 
 278:             syslog(LOG_NOTICE, "alias database %srebuilt by %s",
 279:                 automatic ? "auto" : "", username());
 280:         }
 281: #endif LOG
 282:         readaliases(aliasfile, TRUE);
 283:     }
 284: # else DBM
 285:     readaliases(aliasfile, init);
 286: # endif DBM
 287: }
 288: /*
 289: **  READALIASES -- read and process the alias file.
 290: **
 291: **	This routine implements the part of initaliases that occurs
 292: **	when we are not going to use the DBM stuff.
 293: **
 294: **	Parameters:
 295: **		aliasfile -- the pathname of the alias file master.
 296: **		init -- if set, initialize the DBM stuff.
 297: **
 298: **	Returns:
 299: **		none.
 300: **
 301: **	Side Effects:
 302: **		Reads aliasfile into the symbol table.
 303: **		Optionally, builds the .dir & .pag files.
 304: */
 305: 
 306: static
 307: readaliases(aliasfile, init)
 308:     char *aliasfile;
 309:     bool init;
 310: {
 311:     register char *p;
 312:     char *rhs;
 313:     bool skipping;
 314:     int naliases, longest;
 315:     long bytes;
 316:     FILE *af;
 317:     int (*oldsigint)();
 318:     ADDRESS al, bl;
 319:     register STAB *s;
 320:     char line[BUFSIZ];
 321: 
 322:     if ((af = fopen(aliasfile, "r")) == NULL)
 323:     {
 324: # ifdef DEBUG
 325:         if (tTd(27, 1))
 326:             printf("Can't open %s\n", aliasfile);
 327: # endif
 328:         errno = 0;
 329:         NoAlias++;
 330:         return;
 331:     }
 332: 
 333: # ifdef DBM
 334: # ifdef FLOCK
 335:     /* see if someone else is rebuilding the alias file already */
 336:     if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
 337:     {
 338:         /* yes, they are -- wait until done and then return */
 339:         message(Arpa_Info, "Alias file is already being rebuilt");
 340:         if (OpMode != MD_INITALIAS)
 341:         {
 342:             /* wait for other rebuild to complete */
 343:             (void) flock(fileno(af), LOCK_EX);
 344:         }
 345:         (void) fclose(af);
 346:         errno = 0;
 347:         return;
 348:     }
 349: # endif FLOCK
 350: # endif DBM
 351: 
 352:     /*
 353: 	**  If initializing, create the new DBM files.
 354: 	*/
 355: 
 356:     if (init)
 357:     {
 358:         oldsigint = signal(SIGINT, SIG_IGN);
 359:         (void) strcpy(line, aliasfile);
 360:         (void) strcat(line, ".dir");
 361:         if (close(creat(line, DBMMODE)) < 0)
 362:         {
 363:             syserr("cannot make %s", line);
 364:             (void) signal(SIGINT, oldsigint);
 365:             return;
 366:         }
 367:         (void) strcpy(line, aliasfile);
 368:         (void) strcat(line, ".pag");
 369:         if (close(creat(line, DBMMODE)) < 0)
 370:         {
 371:             syserr("cannot make %s", line);
 372:             (void) signal(SIGINT, oldsigint);
 373:             return;
 374:         }
 375:         dbminit(aliasfile);
 376:     }
 377: 
 378:     /*
 379: 	**  Read and interpret lines
 380: 	*/
 381: 
 382:     FileName = aliasfile;
 383:     LineNumber = 0;
 384:     naliases = bytes = longest = 0;
 385:     skipping = FALSE;
 386:     while (fgets(line, sizeof (line), af) != NULL)
 387:     {
 388:         int lhssize, rhssize;
 389: 
 390:         LineNumber++;
 391:         p = index(line, '\n');
 392:         if (p != NULL)
 393:             *p = '\0';
 394:         switch (line[0])
 395:         {
 396:           case '#':
 397:           case '\0':
 398:             skipping = FALSE;
 399:             continue;
 400: 
 401:           case ' ':
 402:           case '\t':
 403:             if (!skipping)
 404:                 syserr("Non-continuation line starts with space");
 405:             skipping = TRUE;
 406:             continue;
 407:         }
 408:         skipping = FALSE;
 409: 
 410:         /*
 411: 		**  Process the LHS
 412: 		**	Find the final colon, and parse the address.
 413: 		**	It should resolve to a local name -- this will
 414: 		**	be checked later (we want to optionally do
 415: 		**	parsing of the RHS first to maximize error
 416: 		**	detection).
 417: 		*/
 418: 
 419:         for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
 420:             continue;
 421:         if (*p++ != ':')
 422:         {
 423:             syserr("missing colon");
 424:             continue;
 425:         }
 426:         if (parseaddr(line, &al, 1, ':') == NULL)
 427:         {
 428:             syserr("illegal alias name");
 429:             continue;
 430:         }
 431:         loweraddr(&al);
 432: 
 433:         /*
 434: 		**  Process the RHS.
 435: 		**	'al' is the internal form of the LHS address.
 436: 		**	'p' points to the text of the RHS.
 437: 		*/
 438: 
 439:         rhs = p;
 440:         for (;;)
 441:         {
 442:             register char c;
 443: 
 444:             if (init && CheckAliases)
 445:             {
 446:                 /* do parsing & compression of addresses */
 447:                 while (*p != '\0')
 448:                 {
 449:                     extern char *DelimChar;
 450: 
 451:                     while (isspace(*p) || *p == ',')
 452:                         p++;
 453:                     if (*p == '\0')
 454:                         break;
 455:                     if (parseaddr(p, &bl, -1, ',') == NULL)
 456:                         usrerr("%s... bad address", p);
 457:                     if (bl.q_host && bl.q_host[0])
 458:                         free(bl.q_host);
 459:                     p = DelimChar;
 460:                 }
 461:             }
 462:             else
 463:             {
 464:                 p = &p[strlen(p)];
 465:                 if (p[-1] == '\n')
 466:                     *--p = '\0';
 467:             }
 468: 
 469:             /* see if there should be a continuation line */
 470:             c = fgetc(af);
 471:             if (!feof(af))
 472:                 (void) ungetc(c, af);
 473:             if (c != ' ' && c != '\t')
 474:                 break;
 475: 
 476:             /* read continuation line */
 477:             if (fgets(p, sizeof line - (p - line), af) == NULL)
 478:                 break;
 479:             LineNumber++;
 480:         }
 481:         if (al.q_mailer != LocalMailer)
 482:         {
 483:             syserr("cannot alias non-local names");
 484:             continue;
 485:         }
 486: 
 487:         /*
 488: 		**  Insert alias into symbol table or DBM file
 489: 		*/
 490: 
 491:         lhssize = strlen(al.q_user) + 1;
 492:         rhssize = strlen(rhs) + 1;
 493: 
 494: # ifdef DBM
 495:         if (init)
 496:         {
 497:             DATUM key, content;
 498: 
 499:             key.dsize = lhssize;
 500:             key.dptr = al.q_user;
 501:             content.dsize = rhssize;
 502:             content.dptr = rhs;
 503:             store(key, content);
 504:             if (al.q_paddr)
 505:                 free(al.q_paddr);
 506:             if (al.q_host)
 507:                 free(al.q_host);
 508:             if (al.q_user)
 509:                 free(al.q_user);
 510:         }
 511:         else
 512: # endif DBM
 513:         {
 514:             s = stab(al.q_user, ST_ALIAS, ST_ENTER);
 515:             s->s_alias = newstr(rhs);
 516:         }
 517: 
 518:         /* statistics */
 519:         naliases++;
 520:         bytes += lhssize + rhssize;
 521:         if (rhssize > longest)
 522:             longest = rhssize;
 523:     }
 524: 
 525: # ifdef DBM
 526:     if (init)
 527:     {
 528:         /* add the distinquished alias "@" */
 529:         DATUM key;
 530: 
 531:         key.dsize = 2;
 532:         key.dptr = "@";
 533:         store(key, key);
 534: 
 535:         /* restore the old signal */
 536:         (void) signal(SIGINT, oldsigint);
 537:     }
 538: # endif DBM
 539: 
 540:     /* closing the alias file drops the lock */
 541:     (void) fclose(af);
 542:     CurEnv->e_to = NULL;
 543:     FileName = NULL;
 544:     message(Arpa_Info, "%d aliases, longest %d bytes, %ld bytes total",
 545:             naliases, longest, bytes);
 546: # ifdef LOG
 547:     if (LogLevel >= 8)
 548:         syslog(LOG_INFO, "%d aliases, longest %d bytes, %ld bytes total",
 549:             naliases, longest, bytes);
 550: # endif LOG
 551: }
 552: /*
 553: **  FORWARD -- Try to forward mail
 554: **
 555: **	This is similar but not identical to aliasing.
 556: **
 557: **	Parameters:
 558: **		user -- the name of the user who's mail we would like
 559: **			to forward to.  It must have been verified --
 560: **			i.e., the q_home field must have been filled
 561: **			in.
 562: **		sendq -- a pointer to the head of the send queue to
 563: **			put this user's aliases in.
 564: **
 565: **	Returns:
 566: **		none.
 567: **
 568: **	Side Effects:
 569: **		New names are added to send queues.
 570: */
 571: 
 572: forward(user, sendq)
 573:     ADDRESS *user;
 574:     ADDRESS **sendq;
 575: {
 576:     char buf[60];
 577:     extern bool safefile();
 578: 
 579: # ifdef DEBUG
 580:     if (tTd(27, 1))
 581:         printf("forward(%s)\n", user->q_paddr);
 582: # endif DEBUG
 583: 
 584:     if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
 585:         return;
 586: # ifdef DEBUG
 587:     if (user->q_home == NULL)
 588:         syserr("forward: no home");
 589: # endif DEBUG
 590: 
 591:     /* good address -- look for .forward file in home */
 592:     define('z', user->q_home, CurEnv);
 593:     expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
 594:     if (!safefile(buf, user->q_uid, S_IREAD))
 595:         return;
 596: 
 597:     /* we do have an address to forward to -- do it */
 598:     include(buf, "forwarding", user, sendq);
 599: }

Defined functions

alias defined in line 67; used 1 times
aliaslookup defined in line 128; used 5 times
forward defined in line 572; used 1 times
readaliases defined in line 306; used 2 times

Defined variables

SccsId defined in line 25; never used

Defined macros

DBMMODE defined in line 167; used 2 times
Last modified: 1991-08-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5131
Valid CSS Valid XHTML 1.0 Strict