1: /*
   2:  * Copyright (c) 1988 Regents of the University of California.
   3:  * All rights reserved.
   4:  *
   5:  * Redistribution and use in source and binary forms are permitted
   6:  * provided that this notice is preserved and that due credit is given
   7:  * to the University of California at Berkeley. The name of the University
   8:  * may not be used to endorse or promote products derived from this
   9:  * software without specific prior written permission. This software
  10:  * is provided ``as is'' without express or implied warranty.
  11:  *
  12:  *  Sendmail
  13:  *  Copyright (c) 1983  Eric P. Allman
  14:  *  Berkeley, California
  15:  */
  16: 
  17: #if !defined(lint) && !defined(NOSCCS)
  18: #ifdef DBM
  19: static char sccsid[] = "@(#)alias.c	5.15 (Berkeley) 4/1/88 (with DBM)";
  20: #else
  21: static char sccsid[] = "@(#)alias.c	5.15 (Berkeley) 4/1/88 (without DBM)";
  22: #endif
  23: #endif /* not lint */
  24: 
  25: # include <pwd.h>
  26: # include <sys/types.h>
  27: # include <sys/stat.h>
  28: # include <signal.h>
  29: # include <errno.h>
  30: # include "sendmail.h"
  31: # include <sys/file.h>
  32: 
  33: /*
  34: **  ALIAS -- Compute aliases.
  35: **
  36: **	Scans the alias file for an alias for the given address.
  37: **	If found, it arranges to deliver to the alias list instead.
  38: **	Uses libdbm database if -DDBM.
  39: **
  40: **	Parameters:
  41: **		a -- address to alias.
  42: **		sendq -- a pointer to the head of the send queue
  43: **			to put the aliases in.
  44: **
  45: **	Returns:
  46: **		none
  47: **
  48: **	Side Effects:
  49: **		Aliases found are expanded.
  50: **
  51: **	Notes:
  52: **		If NoAlias (the "-n" flag) is set, no aliasing is
  53: **			done.
  54: **
  55: **	Deficiencies:
  56: **		It should complain about names that are aliased to
  57: **			nothing.
  58: */
  59: 
  60: 
  61: #ifdef DBM
  62: typedef struct
  63: {
  64:     char    *dptr;
  65:     int dsize;
  66: } DATUM;
  67: extern DATUM fetch();
  68: #endif DBM
  69: 
  70: alias(a, sendq)
  71:     register ADDRESS *a;
  72:     ADDRESS **sendq;
  73: {
  74:     register char *p;
  75:     extern char *aliaslookup();
  76: 
  77: # ifdef DEBUG
  78:     if (tTd(27, 1))
  79:         printf("alias(%s)\n", a->q_paddr);
  80: # endif
  81: 
  82:     /* don't realias already aliased names */
  83:     if (bitset(QDONTSEND, a->q_flags))
  84:         return;
  85: 
  86:     CurEnv->e_to = a->q_paddr;
  87: 
  88:     /*
  89: 	**  Look up this name
  90: 	*/
  91: 
  92:     if (NoAlias)
  93:         p = NULL;
  94:     else
  95:         p = aliaslookup(a->q_user);
  96:     if (p == NULL)
  97:         return;
  98: 
  99:     /*
 100: 	**  Match on Alias.
 101: 	**	Deliver to the target list.
 102: 	*/
 103: 
 104: # ifdef DEBUG
 105:     if (tTd(27, 1))
 106:         printf("%s (%s, %s) aliased to %s\n",
 107:             a->q_paddr, a->q_host, a->q_user, p);
 108: # endif
 109:     message(Arpa_Info, "aliased to %s", p);
 110:     AliasLevel++;
 111:     sendtolist(p, a, sendq);
 112:     AliasLevel--;
 113: }
 114: /*
 115: **  ALIASLOOKUP -- look up a name in the alias file.
 116: **
 117: **	Parameters:
 118: **		name -- the name to look up.
 119: **
 120: **	Returns:
 121: **		the value of name.
 122: **		NULL if unknown.
 123: **
 124: **	Side Effects:
 125: **		none.
 126: **
 127: **	Warnings:
 128: **		The return value will be trashed across calls.
 129: */
 130: 
 131: char *
 132: aliaslookup(name)
 133:     char *name;
 134: {
 135: # ifdef DBM
 136:     DATUM rhs, lhs;
 137: 
 138:     /* create a key for fetch */
 139:     lhs.dptr = name;
 140:     lhs.dsize = strlen(name) + 1;
 141:     rhs = fetch(lhs);
 142:     return (rhs.dptr);
 143: # else DBM
 144:     register STAB *s;
 145: 
 146:     s = stab(name, ST_ALIAS, ST_FIND);
 147:     if (s == NULL)
 148:         return (NULL);
 149:     return (s->s_alias);
 150: # endif DBM
 151: }
 152: /*
 153: **  INITALIASES -- initialize for aliasing
 154: **
 155: **	Very different depending on whether we are running DBM or not.
 156: **
 157: **	Parameters:
 158: **		aliasfile -- location of aliases.
 159: **		init -- if set and if DBM, initialize the DBM files.
 160: **
 161: **	Returns:
 162: **		none.
 163: **
 164: **	Side Effects:
 165: **		initializes aliases:
 166: **		if DBM:  opens the database.
 167: **		if ~DBM: reads the aliases into the symbol table.
 168: */
 169: 
 170: # define DBMMODE    0666
 171: 
 172: initaliases(aliasfile, init)
 173:     char *aliasfile;
 174:     bool init;
 175: {
 176: #ifdef DBM
 177:     int atcnt;
 178:     time_t modtime;
 179:     bool automatic = FALSE;
 180:     char buf[MAXLINE];
 181: #endif DBM
 182:     struct stat stb;
 183:     static bool initialized = FALSE;
 184: 
 185:     if (initialized)
 186:         return;
 187:     initialized = TRUE;
 188: 
 189:     if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
 190:     {
 191:         if (aliasfile != NULL && init)
 192:             syserr("Cannot open %s", aliasfile);
 193:         NoAlias = TRUE;
 194:         errno = 0;
 195:         return;
 196:     }
 197: 
 198: # ifdef DBM
 199:     /*
 200: 	**  Check to see that the alias file is complete.
 201: 	**	If not, we will assume that someone died, and it is up
 202: 	**	to us to rebuild it.
 203: 	*/
 204: 
 205:     if (!init)
 206:         dbminit(aliasfile);
 207:     atcnt = SafeAlias * 2;
 208:     if (atcnt > 0)
 209:     {
 210:         while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
 211:         {
 212:             /*
 213: 			**  Reinitialize alias file in case the new
 214: 			**  one is mv'ed in instead of cp'ed in.
 215: 			**
 216: 			**	Only works with new DBM -- old one will
 217: 			**	just consume file descriptors forever.
 218: 			**	If you have a dbmclose() it can be
 219: 			**	added before the sleep(30).
 220: 			*/
 221: 
 222:             sleep(30);
 223: # ifdef NDBM
 224:             dbminit(aliasfile);
 225: # endif NDBM
 226:         }
 227:     }
 228:     else
 229:         atcnt = 1;
 230: 
 231:     /*
 232: 	**  See if the DBM version of the file is out of date with
 233: 	**  the text version.  If so, go into 'init' mode automatically.
 234: 	**	This only happens if our effective userid owns the DBM
 235: 	**	version or if the mode of the database is 666 -- this
 236: 	**	is an attempt to avoid protection problems.  Note the
 237: 	**	unpalatable hack to see if the stat succeeded.
 238: 	*/
 239: 
 240:     modtime = stb.st_mtime;
 241:     (void) strcpy(buf, aliasfile);
 242:     (void) strcat(buf, ".pag");
 243:     stb.st_ino = 0;
 244:     if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
 245:     {
 246:         errno = 0;
 247:         if (AutoRebuild && stb.st_ino != 0 &&
 248:             ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid()))
 249:         {
 250:             init = TRUE;
 251:             automatic = TRUE;
 252:             message(Arpa_Info, "rebuilding alias database");
 253: #ifdef LOG
 254:             if (LogLevel >= 7)
 255:                 syslog(LOG_INFO, "rebuilding alias database");
 256: #endif LOG
 257:         }
 258:         else
 259:         {
 260: #ifdef LOG
 261:             if (LogLevel >= 7)
 262:                 syslog(LOG_INFO, "alias database out of date");
 263: #endif LOG
 264:             message(Arpa_Info, "Warning: alias database out of date");
 265:         }
 266:     }
 267: 
 268: 
 269:     /*
 270: 	**  If necessary, load the DBM file.
 271: 	**	If running without DBM, load the symbol table.
 272: 	*/
 273: 
 274:     if (init)
 275:     {
 276: #ifdef LOG
 277:         if (LogLevel >= 6)
 278:         {
 279:             extern char *username();
 280: 
 281:             syslog(LOG_NOTICE, "alias database %srebuilt by %s",
 282:                 automatic ? "auto" : "", username());
 283:         }
 284: #endif LOG
 285:         readaliases(aliasfile, TRUE);
 286:     }
 287: # else DBM
 288:     readaliases(aliasfile, init);
 289: # endif DBM
 290: }
 291: /*
 292: **  READALIASES -- read and process the alias file.
 293: **
 294: **	This routine implements the part of initaliases that occurs
 295: **	when we are not going to use the DBM stuff.
 296: **
 297: **	Parameters:
 298: **		aliasfile -- the pathname of the alias file master.
 299: **		init -- if set, initialize the DBM stuff.
 300: **
 301: **	Returns:
 302: **		none.
 303: **
 304: **	Side Effects:
 305: **		Reads aliasfile into the symbol table.
 306: **		Optionally, builds the .dir & .pag files.
 307: */
 308: 
 309: static
 310: readaliases(aliasfile, init)
 311:     char *aliasfile;
 312:     bool init;
 313: {
 314:     register char *p;
 315:     char *rhs;
 316:     bool skipping;
 317:     int naliases, bytes, longest;
 318:     FILE *af;
 319:     int (*oldsigint)();
 320:     ADDRESS al, bl;
 321:     register STAB *s;
 322:     char line[BUFSIZ];
 323: 
 324:     if ((af = fopen(aliasfile, "r")) == NULL)
 325:     {
 326: # ifdef DEBUG
 327:         if (tTd(27, 1))
 328:             printf("Can't open %s\n", aliasfile);
 329: # endif
 330:         errno = 0;
 331:         NoAlias++;
 332:         return;
 333:     }
 334: 
 335: # ifdef DBM
 336:     /* see if someone else is rebuilding the alias file already */
 337:     if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
 338:     {
 339:         /* yes, they are -- wait until done and then return */
 340:         message(Arpa_Info, "Alias file is already being rebuilt");
 341:         if (OpMode != MD_INITALIAS)
 342:         {
 343:             /* wait for other rebuild to complete */
 344:             (void) flock(fileno(af), LOCK_EX);
 345:         }
 346:         (void) fclose(af);
 347:         errno = 0;
 348:         return;
 349:     }
 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:                     p = DelimChar;
 458:                 }
 459:             }
 460:             else
 461:             {
 462:                 p = &p[strlen(p)];
 463:                 if (p[-1] == '\n')
 464:                     *--p = '\0';
 465:             }
 466: 
 467:             /* see if there should be a continuation line */
 468:             c = fgetc(af);
 469:             if (!feof(af))
 470:                 (void) ungetc(c, af);
 471:             if (c != ' ' && c != '\t')
 472:                 break;
 473: 
 474:             /* read continuation line */
 475:             if (fgets(p, sizeof line - (p - line), af) == NULL)
 476:                 break;
 477:             LineNumber++;
 478:         }
 479:         if (al.q_mailer != LocalMailer)
 480:         {
 481:             syserr("cannot alias non-local names");
 482:             continue;
 483:         }
 484: 
 485:         /*
 486: 		**  Insert alias into symbol table or DBM file
 487: 		*/
 488: 
 489:         lhssize = strlen(al.q_user) + 1;
 490:         rhssize = strlen(rhs) + 1;
 491: 
 492: # ifdef DBM
 493:         if (init)
 494:         {
 495:             DATUM key, content;
 496: 
 497:             key.dsize = lhssize;
 498:             key.dptr = al.q_user;
 499:             content.dsize = rhssize;
 500:             content.dptr = rhs;
 501:             store(key, content);
 502:         }
 503:         else
 504: # endif DBM
 505:         {
 506:             s = stab(al.q_user, ST_ALIAS, ST_ENTER);
 507:             s->s_alias = newstr(rhs);
 508:         }
 509: 
 510:         /* statistics */
 511:         naliases++;
 512:         bytes += lhssize + rhssize;
 513:         if (rhssize > longest)
 514:             longest = rhssize;
 515:     }
 516: 
 517: # ifdef DBM
 518:     if (init)
 519:     {
 520:         /* add the distinquished alias "@" */
 521:         DATUM key;
 522: 
 523:         key.dsize = 2;
 524:         key.dptr = "@";
 525:         store(key, key);
 526: 
 527:         /* restore the old signal */
 528:         (void) signal(SIGINT, oldsigint);
 529:     }
 530: # endif DBM
 531: 
 532:     /* closing the alias file drops the lock */
 533:     (void) fclose(af);
 534:     CurEnv->e_to = NULL;
 535:     FileName = NULL;
 536:     message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
 537:             naliases, longest, bytes);
 538: # ifdef LOG
 539:     if (LogLevel >= 8)
 540:         syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
 541:             naliases, longest, bytes);
 542: # endif LOG
 543: }
 544: /*
 545: **  FORWARD -- Try to forward mail
 546: **
 547: **	This is similar but not identical to aliasing.
 548: **
 549: **	Parameters:
 550: **		user -- the name of the user who's mail we would like
 551: **			to forward to.  It must have been verified --
 552: **			i.e., the q_home field must have been filled
 553: **			in.
 554: **		sendq -- a pointer to the head of the send queue to
 555: **			put this user's aliases in.
 556: **
 557: **	Returns:
 558: **		none.
 559: **
 560: **	Side Effects:
 561: **		New names are added to send queues.
 562: */
 563: 
 564: forward(user, sendq)
 565:     ADDRESS *user;
 566:     ADDRESS **sendq;
 567: {
 568:     char buf[60];
 569:     extern bool safefile();
 570: 
 571: # ifdef DEBUG
 572:     if (tTd(27, 1))
 573:         printf("forward(%s)\n", user->q_paddr);
 574: # endif DEBUG
 575: 
 576:     if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
 577:         return;
 578: # ifdef DEBUG
 579:     if (user->q_home == NULL)
 580:         syserr("forward: no home");
 581: # endif DEBUG
 582: 
 583:     /* good address -- look for .forward file in home */
 584:     define('z', user->q_home, CurEnv);
 585:     expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
 586:     if (!safefile(buf, user->q_uid, S_IREAD))
 587:         return;
 588: 
 589:     /* we do have an address to forward to -- do it */
 590:     include(buf, "forwarding", user, sendq);
 591: }

Defined functions

alias defined in line 70; used 1 times
aliaslookup defined in line 131; used 5 times
forward defined in line 564; used 1 times
readaliases defined in line 309; used 2 times

Defined variables

sccsid defined in line 21; never used

Defined macros

DBMMODE defined in line 170; used 2 times
Last modified: 1988-09-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3943
Valid CSS Valid XHTML 1.0 Strict