1 # include <stdio.h> 2 # include <ctype.h> 3 # include <pwd.h> 4 # include "sendmail.h" 5 6 static char SccsId[] = "@(#)alias.c 3.6 08/08/81"; 7 8 /* 9 ** ALIAS -- Compute aliases. 10 ** 11 ** Scans the file ALIASFILE for a set of aliases. 12 ** If found, it arranges to deliver to them. Uses libdbm 13 ** database if -DDBM. 14 ** 15 ** Parameters: 16 ** none 17 ** 18 ** Returns: 19 ** none 20 ** 21 ** Side Effects: 22 ** Aliases found are expanded. 23 ** 24 ** Defined Constants: 25 ** MAXRCRSN -- the maximum recursion depth. 26 ** 27 ** Files: 28 ** ALIASFILE -- the mail aliases. The format is 29 ** a series of lines of the form: 30 ** alias:name1,name2,name3,... 31 ** where 'alias' expands to all of 32 ** 'name[i]'. Continuations begin with 33 ** space or tab. 34 ** ALIASFILE.pag, ALIASFILE.dir: libdbm version 35 ** of alias file. Keys are aliases, datums 36 ** (data?) are name1,name2, ... 37 ** 38 ** Notes: 39 ** If NoAlias (the "-n" flag) is set, no aliasing is 40 ** done. 41 ** 42 ** Deficiencies: 43 ** It should complain about names that are aliased to 44 ** nothing. 45 ** It is unsophisticated about line overflows. 46 */ 47 48 49 # define MAXRCRSN 10 50 51 #ifdef DBM 52 typedef struct 53 { 54 char *dptr; 55 int dsize; 56 } datum; 57 datum lhs, rhs; 58 extern datum fetch(); 59 #endif DBM 60 61 alias() 62 { 63 register ADDRESS *q; 64 ADDRESS *q2; 65 FILE *af; 66 char line[MAXLINE+1]; 67 register char *p; 68 extern int errno; 69 bool didalias; 70 bool gotmatch; 71 auto ADDRESS al; 72 extern bool sameaddr(); 73 extern ADDRESS *parse(); 74 int mno; 75 76 if (NoAlias) 77 return; 78 # ifdef DEBUG 79 if (Debug) 80 printf("--- alias ---\n"); 81 # endif 82 83 /* open alias file if not already open */ 84 #ifndef DBM 85 # ifdef DEBUG 86 if (Debug && (af = fopen("mailaliases", "r")) != NULL) 87 printf(" [using local alias file]\n"); 88 else 89 # endif 90 if ((af = fopen(ALIASFILE, "r")) == NULL) 91 { 92 # ifdef DEBUG 93 if (Debug) 94 printf("Can't open %s\n", ALIASFILE); 95 # endif 96 errno = 0; 97 return; 98 } 99 #else DBM 100 dbminit(ALIASFILE); 101 #endif DBM 102 103 #ifndef DBM 104 /* 105 ** Scan alias file. 106 ** If we find any user that any line matches any user, we 107 ** will send to the line rather than to the user. 108 ** 109 ** We pass through the file several times. Didalias tells 110 ** us if we took some alias on this pass through the file; 111 ** when it goes false at the top of the loop we don't have 112 ** to scan any more. Gotmatch tells the same thing, but 113 ** on a line-by-line basis; it is used for processing 114 ** continuation lines. 115 */ 116 117 do 118 { 119 didalias = FALSE; 120 gotmatch = FALSE; 121 rewind(af); 122 while (fgets(line, sizeof line, af) != NULL) 123 { 124 /* comments begin with `#' */ 125 if (line[0] == '#') 126 continue; 127 128 /* check for continuation lines */ 129 if (isspace(line[0])) 130 { 131 if (gotmatch) 132 { 133 sendto(line, 1); 134 } 135 continue; 136 } 137 gotmatch = FALSE; 138 139 /* 140 ** Check to see if this pseudonym exists. 141 ** Turn the alias into canonical form. 142 ** Then scan the send queue until you 143 ** do (or do not) find that address. 144 */ 145 146 /* Get a canonical form for the alias. */ 147 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 148 continue; 149 if (*p == '\0' || *p == '\n') 150 { 151 syntaxerr: 152 syserr("Bad alias line `%s'", line); 153 continue; 154 } 155 *p++ = '\0'; 156 if (parse(line, &al, -1) == NULL) 157 { 158 *--p = ':'; 159 goto syntaxerr; 160 } 161 162 /* if already queued up, don't realias */ 163 for (q = Mailer[al.q_mailer]->m_sendq; q != NULL; q = q->q_next) 164 { 165 if (sameaddr(&al, q, TRUE)) 166 break; 167 } 168 if (q == NULL || bitset(QDONTSEND, q->q_flags)) 169 continue; 170 171 /* 172 ** Match on Alias. 173 ** Deliver to the target list. 174 ** Remove the alias from the send queue 175 ** and put it on the Alias queue. 176 */ 177 178 # ifdef DEBUG 179 if (Debug) 180 printf("%s (%s, %s) aliased to %s (%s,%s,%s)\n", 181 q->q_paddr, q->q_host, q->q_user, 182 p, al.q_paddr, al.q_host, al.q_user); 183 # endif 184 if (Verbose) 185 message("050", "aliased to %s", p); 186 q->q_flags |= QDONTSEND; 187 didalias++; 188 gotmatch++; 189 sendto(p, 1); 190 } 191 } while (didalias); 192 fclose(af); 193 #else DBM 194 /* 195 ** Scan send queues 196 ** We only have to do this once, since anything we alias 197 ** to is being put at the end of the queue we are 198 ** scanning. 199 */ 200 201 for (mno = 0; Mailer[mno] != NULL; mno++) 202 { 203 for (q = Mailer[mno]->m_sendq; q != NULL; q = q->q_next) 204 { 205 To = q->q_paddr; 206 207 /* don't realias already aliased names */ 208 if (bitset(QDONTSEND, q->q_flags)) 209 continue; 210 211 /* only alias local users */ 212 if (q->q_mailer != 0) 213 continue; 214 215 /* create a key for fetch */ 216 lhs.dptr = q->q_user; 217 lhs.dsize = strlen(q->q_user) + 1; 218 rhs = fetch(lhs); 219 220 /* find this alias? */ 221 p = rhs.dptr; 222 if (p == NULL) 223 continue; 224 225 /* 226 ** Match on Alias. 227 ** Deliver to the target list. 228 ** Remove the alias from the send queue 229 ** and put it on the Alias queue. 230 */ 231 232 # ifdef DEBUG 233 if (Debug) 234 printf("%s (%s, %s) aliased to %s\n", 235 q->q_paddr, q->q_host, q->q_user, p); 236 # endif 237 if (Verbose) 238 message("050", "aliased to %s", p); 239 q->q_flags |= QDONTSEND; 240 sendto(p, 1); 241 } 242 } 243 #endif DBM 244 } 245 /* 246 ** FORWARD -- Try to forward mail 247 ** 248 ** This is similar but not identical to aliasing. 249 ** 250 ** Currently it is undefined, until the protocol for userinfo 251 ** databases is finalized. 252 ** 253 ** Parameters: 254 ** user -- the name of the user who's mail we 255 ** would like to forward to. 256 ** 257 ** Returns: 258 ** TRUE -- we have forwarded it somewhere. 259 ** FALSE -- not forwarded; go ahead & deliver. 260 ** 261 ** Side Effects: 262 ** New names are added to send queues. 263 */ 264 265 bool 266 forward(user) 267 ADDRESS *user; 268 { 269 register struct passwd *pw; 270 char buf[50]; 271 register FILE *fp; 272 register char *p; 273 extern struct passwd *getpwnam(); 274 extern char *index(); 275 276 if (user->q_mailer != 0) 277 return (FALSE); 278 279 /* find the user's home directory */ 280 pw = getpwnam(user->q_user); 281 if (pw == NULL) 282 { 283 /* bad address -- mark it */ 284 user->q_flags |= QBADADDR; 285 return (FALSE); 286 } 287 288 /* good address -- look for .forward file in home */ 289 user->q_flags |= QGOODADDR; 290 sprintf(buf, "%s/.forward", pw->pw_dir); 291 fp = fopen(buf, "r"); 292 if (fp == NULL) 293 return (FALSE); 294 295 /* we do have an address to forward to -- do it */ 296 fgets(buf, sizeof buf, fp); 297 if ((p = index(buf, '\n')) != NULL) 298 *p = '\0'; 299 fclose(fp); 300 if (buf[0] == '\0') 301 return (FALSE); 302 if (Verbose) 303 message("050", "forwarded to %s", buf); 304 sendto(buf, 1); 305 return (TRUE); 306 } 307