This is alias.c in view mode; [Download] [Up]
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted provided * that: (1) source distributions retain this entire copyright notice and * comment, and (2) distributions including binaries display the following * acknowledgement: ``This product includes software developed by the * University of California, Berkeley and its contributors'' in the * documentation or other materials provided with the distribution and in * all advertising materials mentioning features or use of this software. * Neither the name of the University nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include "sendmail.h" #include <sys/stat.h> #include <errno.h> #ifdef ISC # include <net/errno.h> #endif /* ISC */ #include <pwd.h> #ifdef YP # include <sys/param.h> # ifndef MAXHOSTNAMELEN # define MAXHOSTNAMELEN 64 # endif /* !MAXHOSTNAMELEN */ #endif /* YP */ #ifndef S_IREAD # define S_IREAD _S_IREAD #endif /* !S_IREAD */ #ifdef NeXT #include <aliasdb.h> #endif #ifndef lint # ifdef DBM static char sccsid[] = "@(#)alias.c 5.21 (Berkeley) 6/1/90 (with DBM)"; static char rcsid[] = "@(#)$Id: alias.c,v 5.21.0.24 1991/08/14 16:56:42 paul Exp $ (with DBM)"; # else /* !DBM */ static char sccsid[] = "@(#)alias.c 5.21 (Berkeley) 6/1/90 (without DBM)"; static char rcsid[] = "@(#)$Id: alias.c,v 5.21.0.24 1991/08/14 16:56:42 paul Exp $ (without DBM)"; # endif /* DBM */ #endif /* not lint */ #ifdef __STDC__ static void print_mailer(MAILER *); static void readaliases(int); #else /* !__STDC__ */ static void print_mailer(); static void readaliases(); #endif /* __STDC__ */ /* ** ALIAS -- Compute aliases. ** ** Scans the alias file for an alias for the given address. ** If found, it arranges to deliver to the alias list instead. ** Uses libdbm database if -DDBM. ** ** Parameters: ** a -- address to alias. ** sendq -- a pointer to the head of the send queue ** to put the aliases in. ** ** Returns: ** none ** ** Side Effects: ** Aliases found are expanded. ** ** Notes: ** If NoAlias (the "-n" flag) is set, no aliasing is ** done. ** ** Deficiencies: ** It should complain about names that are aliased to ** nothing. */ #if defined(DBM) && !defined(NDBM) && !defined(OTHERDBM) # ifdef __STDC__ extern XDATUM fetch(XDATUM); # else /* !__STDC__ */ extern XDATUM fetch(); # endif /* __STDC__ */ #endif /* DBM && !NDBM && !OTHERDBM */ void alias(a, sendq) register ADDRESS *a; ADDRESS **sendq; { register char *p; if (tTd(27, 1)) printf("alias(%s)\n", a->q_user); /* don't realias already aliased names */ if (bitset(QDONTSEND, a->q_flags)) return; CurEnv->e_to = a->q_paddr; /* ** Look up this name */ if (NoAlias) p = NULL; else p = aliaslookup(a->q_user); if (p == NULL) return; /* ** Match on Alias. ** Deliver to the target list. */ if (tTd(27, 1)) printf("%s (%s, %s) aliased to %s\n", a->q_paddr, a->q_host, a->q_user, p); message(Arpa_Info, "aliased to %s", p); /* sendtolist() will detect a possible self-reference for this alias */ a->q_flags &= ~QSELFREF; AliasLevel++; sendtolist(p, a, sendq); AliasLevel--; if (!bitset(QSELFREF, a->q_flags)) a->q_flags |= QDONTSEND; } /* ** ALIASLOOKUP -- look up a name in the alias file. ** ** Parameters: ** name -- the name to look up. ** ** Returns: ** the value of name. ** NULL if unknown. ** ** Side Effects: ** none. ** ** Warnings: ** The return value will be trashed across calls ** unless NDBM or OTHERDBM is defined and we're using mapkey(). */ char * aliaslookup(name) char *name; { #ifdef NeXT aliasent *theAlias; #endif #ifdef DBM # if defined(NDBM) || defined(OTHERDBM) char *newname; if (tTd(27, 3)) printf("aliaslookup(\"%s\") => ", name); #ifdef NeXT /* look in the NetInfo database first. If there's no matches there, then continue as normal, by looking first at YP, if enabled, and then the aliases database. */ if (theAlias = alias_getbyname(name)) { int temp=0, length=2; for (temp=0; temp<theAlias->alias_members_len; length += (strlen(theAlias->alias_members[temp++])+1)) ; newname = (char *)xalloc(length); strcpy(newname, theAlias->alias_members[0]); for (temp=1; temp<theAlias->alias_members_len; temp++) { strcat(newname, ","); strcat(newname, theAlias->alias_members[temp]); } } else { #endif newname = mapkey(DB_ALIAS, name, 0, (char *)NULL); #ifdef NeXT } #endif if (tTd(27, 3)) printf("%s\n", newname == NULL ? "NOT_FOUND" : newname); return newname; # else /* !NDBM && !OTHERDBM */ XDATUM rhs, lhs; char *lowname = newstr(name); /* create a key for fetch */ (void) makelower(lowname); lhs.dsize = strlen(name); if (tTd(27, 3)) printf("aliaslookup(\"%s\") => ", name); /* first try key as given */ lhs.dptr = name; rhs = fetch(lhs); if (rhs.dptr == (char *)NULL) { /* try null-terminated version */ lhs.dsize += 1; rhs = fetch(lhs); lhs.dsize -= 1; if (rhs.dptr == (char *)NULL) { /* try lower-case version */ lhs.dptr = lowname; rhs = fetch(lhs); if (rhs.dptr == (char *)NULL) { /* try null-terminated lower-case version */ lhs.dsize += 1; rhs = fetch(lhs); } } } free(lowname); if (tTd(27, 3)) (rhs.dptr) ? printf("%.*s\n", rhs.dsize, rhs.dptr) : printf("NOT_FOUND\n"); return (rhs.dptr); # endif /* NDBM || OTHERDBM */ #else /* !DBM */ register STAB *s; s = stab(name, ST_ALIAS, ST_FIND); if (tTd(27, 3)) printf("%s\n", s == NULL ? "NOT_FOUND" : s->s_alias); if (s == NULL) return (NULL); return (s->s_alias); #endif /* DBM */ } /* ** INITALIASES -- initialize for aliasing ** ** Very different depending on whether we are running DBM or not. ** ** Parameters: ** init -- if set and if DBM, initialize the DBM files. ** ** Returns: ** none. ** ** Side Effects: ** initializes aliases: ** if DBM: opens the database. ** if ~DBM: reads the aliases into the symbol table. */ #define DBMMODE 0644 void initaliases(init) bool init; { #ifdef DBM int atcnt; TIME_TYPE modtime; bool automatic = FALSE; char buf[MAXNAME]; #endif /* DBM */ struct stat stb; static bool initialized = FALSE; if (initialized) return; initialized = TRUE; if (AliasFile == NULL || #ifdef YPMARK (AliasFile[0] != YPMARK && #endif /* YPMARK */ stat(AliasFile, &stb) < 0) #ifdef YPMARK ) #endif /* YPMARK */ { if (AliasFile != NULL && init) syserr("Cannot open %s", AliasFile); NoAlias = TRUE; errno = 0; return; } #ifdef DBM /* ** Check to see that the alias file is complete. ** If not, we will assume that someone died, and it is up ** to us to rebuild it. */ # if !defined(NDBM) && !defined(OTHERDBM) if (!init) dbminit(AliasFile); # endif /* !NDBM && !OTHERDBM */ atcnt = SafeAlias * 2; if (atcnt > 0) while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) Xsleep(30); else atcnt = 1; /* ** See if the DBM version of the file is out of date with ** the text version. If so, go into 'init' mode automatically. ** This only happens if our effective userid owns the DBM. ** Note the unpalatable hack to see if the stat succeeded. */ modtime = stb.st_mtime; (void) strcpy(buf, AliasFile); (void) strcat(buf, DB_PAGEXT); stb.st_ino = 0; if (!init && # ifdef YPMARK AliasFile[0] != YPMARK && # endif /* YPMARK */ (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) { errno = 0; if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) { init = TRUE; automatic = TRUE; message(Arpa_Info, "rebuilding alias database"); # ifdef LOG if (LogLevel >= 7) syslog(LOG_INFO, "rebuilding alias database"); # endif /* LOG */ } else { # ifdef LOG if (LogLevel >= 7) syslog(LOG_INFO, "alias database out of date"); # endif /* LOG */ message(Arpa_Info, "Warning: alias database out of date"); } } /* ** If necessary, load the DBM file. ** If running without DBM, load the symbol table. */ if (init) { # ifdef LOG if (LogLevel >= 6) syslog(LOG_NOTICE, "alias database %srebuilt by %s", automatic ? "auto" : "", username()); # endif /* LOG */ readaliases(TRUE); } #else /* !DBM */ readaliases(init); #endif /* DBM */ } /* ** READALIASES -- read and process the alias file. ** ** This routine implements the part of initaliases that occurs ** when we are not going to use the DBM stuff. ** ** Parameters: ** init -- if set, initialize the DBM stuff. ** ** Returns: ** none. ** ** Side Effects: ** Reads AliasFile into the symbol table. ** Optionally, builds the .dir & .pag files. */ static void readaliases(init) bool init; { register char *p; char *rhs; bool skipping; int naliases, bytes, longest; FILE *af; SIG_TYPE (*oldsigint)(); ADDRESS al, bl; register STAB *s; char line[BUFSIZ]; char longest_lhs[BUFSIZ]; #ifdef YPMARK if (AliasFile[0] == YPMARK) { if (tTd(27, 1)) printf("Can't reinit YP databases: \"%s\"\n", AliasFile); /* reuse old aliases */ errno = 0; return; } #endif /* YPMARK */ /* * We can't get an exclusive lock on a file that isn't opened for * writing on most systems - sigh! */ if ((af = fopen(AliasFile, "r+")) == NULL) { if (tTd(27, 1)) printf("Can't open %s\n", AliasFile); errno = 0; NoAlias++; return; } #ifdef DBM /* see if someone else is rebuilding the alias file already */ if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) { /* yes, they are -- wait until done and then return */ message(Arpa_Info, "Alias file is already being rebuilt"); if (OpMode != MD_INITALIAS) { /* wait for other rebuild to complete */ (void) flock(fileno(af), LOCK_EX); } (void) fclose(af); errno = 0; return; } #endif /* DBM */ /* ** If initializing, create the new DBM files. */ if (init) { oldsigint = signal(SIGINT, SIG_IGN); (void) strcpy(line, AliasFile); (void) strcat(line, DB_PAGEXT); if (close(creat(line, DBMMODE)) < 0) { syserr("cannot make %s", line); (void) signal(SIGINT, oldsigint); return; } (void) strcpy(line, AliasFile); (void) strcat(line, DB_DIREXT); if (close(creat(line, DBMMODE)) < 0) { syserr("cannot make %s", line); (void) signal(SIGINT, oldsigint); return; } #if defined(NDBM) || defined(OTHERDBM) (void) mapinit(DB_ALIAS); #else /* !NDBM && !OTHERDBM */ dbminit(AliasFile); #endif /* NDBM || OTHERDBM */ } /* ** Read and interpret lines */ FileName = AliasFile; LineNumber = 0; naliases = bytes = longest = 0; *longest_lhs = '\0'; skipping = FALSE; while (fgets(line, sizeof (line), af) != NULL) { int lhssize, rhssize; LineNumber++; p = index(line, '\n'); if (p != NULL) *p = '\0'; switch (line[0]) { case '#': case '\0': skipping = FALSE; continue; case ' ': case '\t': if (!skipping) syserr("Non-continuation line starts with space"); skipping = TRUE; continue; } skipping = FALSE; /* ** Process the LHS ** Find the first colon, and parse the address. ** It should resolve to a local name -- this will ** be checked later (we want to optionally do ** parsing of the RHS first to maximize error ** detection). */ for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) continue; if (*p++ != ':') { syserr("missing colon"); continue; } if (parseaddr(line, &al, 1, ':') == NULL) { syserr("illegal alias name"); continue; } loweraddr(&al); /* ** Process the RHS. ** 'al' is the internal form of the LHS address. ** 'p' points to the text of the RHS. */ rhs = p; for (;;) { register char c; if (init && CheckAliases) { /* do parsing & compression of addresses */ while (*p != '\0') { extern char *DelimChar; while (isspace(*p) || *p == ',') p++; if (*p == '\0') break; if (parseaddr(p, &bl, -1, ',') == NULL) usrerr("%s... bad address", p); p = DelimChar; } } else { p = &p[strlen(p)]; if (p[-1] == '\n') *--p = '\0'; } /* see if there should be a continuation line */ c = fgetc(af); if (!feof(af)) (void) ungetc(c, af); if (c != ' ' && c != '\t') break; /* read continuation line */ if (fgets(p, sizeof line - (p - line), af) == NULL) break; LineNumber++; } if (al.q_mailer != LocalMailer) { syserr("cannot alias non-local names"); { printf("Mailer al.q_mailer:\n"); print_mailer(al.q_mailer); printf("\nMailer LocalMailer:\n"); print_mailer(LocalMailer); } continue; } /* ** Insert alias into symbol table or DBM file */ lhssize = strlen(al.q_user); rhssize = strlen(rhs); #ifndef NO_PADDING lhssize++; rhssize++; #endif /* !NO_PADDING */ #ifdef DBM if (init) { XDATUM key, content; key.dsize = lhssize; key.dptr = al.q_user; content.dsize = rhssize; content.dptr = rhs; if ( # if defined(NDBM) || defined(OTHERDBM) dbm_store(AliasDbm, key, content, DBM_REPLACE) # else /* !NDBM && !OTHERDBM */ store(key, content) # endif /* NDBM || OTHERDBM */ < 0) syserr("DBM store of %s (size %d) failed", al.q_user, (lhssize+rhssize)); } else #endif /* DBM */ { s = stab(al.q_user, ST_ALIAS, ST_ENTER); s->s_alias = newstr(rhs); } /* statistics */ naliases++; bytes += lhssize + rhssize; if ((rhssize + lhssize) > longest) { longest = rhssize + lhssize; (void) strcpy(longest_lhs, al.q_user); } } #ifdef DBM if (init) { XDATUM key; # ifdef YP XDATUM content; char Now[MAXHOSTNAMELEN+1]; /* add the YP stamps. N.B., don't pad the lengths by 1! */ gethostname (Now, MAXHOSTNAMELEN); key.dsize = strlen ("YP_MASTER_NAME"); key.dptr = "YP_MASTER_NAME"; content.dsize = strlen (Now); content.dptr = Now; # if defined(NDBM) || defined(OTHERDBM) (void) dbm_store(AliasDbm, key, content, DBM_INSERT); # else /* !NDBM && !OTHERDBM */ store(key, content); # endif /* NDBM || OTHERDBM */ (void) sprintf (Now, "%010u", time(0)); key.dsize = strlen ("YP_LAST_MODIFIED"); key.dptr = "YP_LAST_MODIFIED"; content.dsize = strlen (Now); content.dptr = Now; # if defined(NDBM) || defined(OTHERDBM) (void) dbm_store(AliasDbm, key, content, DBM_INSERT); # else /* !NDBM && !OTHERDBM */ store(key, Now); # endif /* NDBM || OTHERDBM */ # endif /* YP */ /* add the distinquished alias "@" */ key.dsize = 2; key.dptr = "@"; # if defined(NDBM) || defined(OTHERDBM) (void) dbm_store(AliasDbm, key, key, DBM_INSERT); # else /* !NDBM && !OTHERDBM */ store(key, key); # endif /* NDBM || OTHERDBM */ /* restore the old signal */ (void) signal(SIGINT, oldsigint); } #endif /* DBM */ /* closing the alias file drops the lock */ (void) fclose(af); CurEnv->e_to = NULL; FileName = NULL; message(Arpa_Info, "%d aliases, longest (%s) %d bytes, %d bytes total", naliases, longest_lhs, longest, bytes); #ifdef LOG if (LogLevel >= 8) syslog(LOG_INFO, "%d aliases, longest (%s) %d bytes, %d bytes total", naliases, longest_lhs, longest, bytes); #endif /* LOG */ } /* ** FORWARD -- Try to forward mail ** ** This is similar but not identical to aliasing. ** ** Parameters: ** user -- the name of the user who's mail we would like ** to forward to. It must have been verified -- ** i.e., the q_home field must have been filled ** in. ** sendq -- a pointer to the head of the send queue to ** put this user's aliases in. ** ** Returns: ** none. ** ** Side Effects: ** New names are added to send queues. */ void forward(user, sendq) ADDRESS *user; ADDRESS **sendq; { char buf[60]; if (tTd(27, 1)) printf("forward(%s)\n", user->q_paddr); if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) return; if (user->q_home == NULL) syserr("forward: no home"); /* good address -- look for .forward file in home */ define('z', user->q_home, CurEnv); expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv); if (!safefile(buf, user->q_uid, S_IREAD)) return; /* * we do have an address to forward to -- do it but * don't carry over selfref from alias. */ user->q_flags &= ~QSELFREF; include(buf, "forwarding", user, sendq); } /* ** PRINT_MAILER -- Print contents of struct mailer ** ** This is for debugging ** ** Parameters: ** Mpnt -- pointer to struct mailer ** ** Returns: ** none. ** ** Side Effects: ** none. */ static void print_mailer(Mpnt) MAILER *Mpnt; { register int i; register char **j; if (Mpnt == (MAILER *) NULL) { printf("Null MAILER pointer\n"); return; } printf("m_name (symbolic name) %s\n", (Mpnt->m_name == (char *)NULL) ? "NULL" : Mpnt->m_name); printf("m_mailer (pathname) %s\n", (Mpnt->m_mailer == (char *)NULL) ? "NULL" : Mpnt->m_mailer); printf("m_flags BITMAP: "); for (i = 0; i < (BITMAPBYTES / sizeof (int)); i++) printf(" %X", Mpnt->m_flags[i]); printf("\n"); printf("m_mno (internal mailer number) %d\n", (int) Mpnt->m_mno); printf("m_argv (template argument vector): "); for (j = Mpnt->m_argv; *j != (char *) NULL; j++) printf(" \"%s\"", *j); printf("\n"); printf("m_se_rwset (rewriting ruleset for envelope senders): %d\n", (int) Mpnt->m_se_rwset); printf("m_sh_rwset (rewriting ruleset for header senders): %d\n", (int) Mpnt->m_sh_rwset); printf("m_re_rwset (rewriting ruleset for envelope recipients): %d\n", (int) Mpnt->m_re_rwset); printf("m_rh_rwset (rewriting ruleset for header recipient): %d\n", (int) Mpnt->m_rh_rwset); printf("m_eol (end of line string) %s\n", (Mpnt->m_eol == (char *)NULL) ? "NULL" : Mpnt->m_eol); printf("m_maxsize (size limit on message to this mailer): %ld\n", Mpnt->m_maxsize); return; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.