1 # include <pwd.h> 2 # include <sys/types.h> 3 # include <sys/stat.h> 4 # include "sendmail.h" 5 6 # ifdef DBM 7 static char SccsId[] = "@(#)alias.c 3.19 09/06/81 (with DBM)"; 8 # else DBM 9 static char SccsId[] = "@(#)alias.c 3.19 09/06/81 (without DBM)"; 10 # endif DBM 11 12 /* 13 ** ALIAS -- Compute aliases. 14 ** 15 ** Scans the file /usr/lib/aliases for a set of aliases. 16 ** If found, it arranges to deliver to them. Uses libdbm 17 ** database if -DDBM. 18 ** 19 ** Parameters: 20 ** a -- address to alias. 21 ** 22 ** Returns: 23 ** none 24 ** 25 ** Side Effects: 26 ** Aliases found are expanded. 27 ** 28 ** Files: 29 ** /usr/lib/aliases -- the mail aliases. The format is 30 ** a series of lines of the form: 31 ** alias:name1,name2,name3,... 32 ** where 'alias' expands to all of 33 ** 'name[i]'. Continuations begin with 34 ** space or tab. 35 ** /usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version 36 ** of alias file. Keys are aliases, datums 37 ** (data?) are name1,name2, ... 38 ** 39 ** Notes: 40 ** If NoAlias (the "-n" flag) is set, no aliasing is 41 ** done. 42 ** 43 ** Deficiencies: 44 ** It should complain about names that are aliased to 45 ** nothing. 46 ** It is unsophisticated about line overflows. 47 */ 48 49 50 #ifdef DBM 51 typedef struct 52 { 53 char *dptr; 54 int dsize; 55 } DATUM; 56 DATUM lhs, rhs; 57 extern DATUM fetch(); 58 #endif DBM 59 60 alias(a) 61 register ADDRESS *a; 62 { 63 register char *p; 64 # ifndef DBM 65 register STAB *s; 66 # endif DBM 67 68 if (NoAlias) 69 return; 70 # ifdef DEBUG 71 if (Debug) 72 printf("alias(%s)\n", a->q_paddr); 73 # endif 74 75 /* don't realias already aliased names */ 76 if (bitset(QDONTSEND, a->q_flags)) 77 return; 78 79 To = a->q_paddr; 80 81 /* 82 ** Look up this name 83 */ 84 85 # ifdef DBM 86 /* create a key for fetch */ 87 lhs.dptr = a->q_user; 88 lhs.dsize = strlen(a->q_user) + 1; 89 rhs = fetch(lhs); 90 91 /* find this alias? */ 92 p = rhs.dptr; 93 if (p == NULL) 94 return; 95 # else DBM 96 s = stab(a->q_user, ST_ALIAS, ST_FIND); 97 if (s == NULL) 98 return; 99 p = s->s_alias; 100 # endif DBM 101 102 /* 103 ** Match on Alias. 104 ** Deliver to the target list. 105 */ 106 107 # ifdef DEBUG 108 if (Debug) 109 printf("%s (%s, %s) aliased to %s\n", 110 a->q_paddr, a->q_host, a->q_user, p); 111 # endif 112 if (Verbose) 113 message(Arpa_Info, "aliased to %s", p); 114 a->q_flags |= QDONTSEND; 115 AliasLevel++; 116 sendto(p, 1); 117 AliasLevel--; 118 } 119 /* 120 ** INITALIASES -- initialize for aliasing 121 ** 122 ** Very different depending on whether we are running DBM or not. 123 ** 124 ** Parameters: 125 ** aliasfile -- location of aliases. 126 ** init -- if set and if DBM, initialize the DBM files. 127 ** 128 ** Returns: 129 ** none. 130 ** 131 ** Side Effects: 132 ** initializes aliases: 133 ** if DBM: opens the database. 134 ** if ~DBM: reads the aliases into the symbol table. 135 */ 136 137 # define DBMMODE 0666 138 139 initaliases(aliasfile, init) 140 char *aliasfile; 141 bool init; 142 { 143 # ifdef DBM 144 if (init) 145 { 146 char buf[MAXNAME]; 147 148 (void) strcpy(buf, aliasfile); 149 (void) strcat(buf, ".dir"); 150 if (close(creat(buf, DBMMODE)) < 0) 151 { 152 syserr("cannot make %s", buf); 153 return; 154 } 155 (void) strcpy(buf, aliasfile); 156 (void) strcat(buf, ".pag"); 157 if (close(creat(buf, DBMMODE)) < 0) 158 { 159 syserr("cannot make %s", buf); 160 return; 161 } 162 } 163 dbminit(aliasfile); 164 if (init) 165 readaliases(aliasfile, TRUE); 166 # else DBM 167 readaliases(aliasfile, init); 168 # endif DBM 169 } 170 /* 171 ** READALIASES -- read and process the alias file. 172 ** 173 ** This routine implements the part of initaliases that occurs 174 ** when we are not going to use the DBM stuff. 175 ** 176 ** Parameters: 177 ** aliasfile -- the pathname of the alias file master. 178 ** init -- if set, initialize the DBM stuff. 179 ** 180 ** Returns: 181 ** none. 182 ** 183 ** Side Effects: 184 ** Reads aliasfile into the symbol table. 185 ** Optionally, builds the .dir & .pag files. 186 */ 187 188 static 189 readaliases(aliasfile, init) 190 char *aliasfile; 191 bool init; 192 { 193 char line[BUFSIZ]; 194 register char *p; 195 char *p2; 196 char *rhs; 197 bool skipping; 198 ADDRESS al, bl; 199 FILE *af; 200 int lineno; 201 register STAB *s; 202 203 if ((af = fopen(aliasfile, "r")) == NULL) 204 { 205 # ifdef DEBUG 206 if (Debug) 207 printf("Can't open %s\n", aliasfile); 208 # endif 209 errno = 0; 210 NoAlias++; 211 return; 212 } 213 214 /* 215 ** Read and interpret lines 216 */ 217 218 lineno = 0; 219 skipping = FALSE; 220 while (fgets(line, sizeof (line), af) != NULL) 221 { 222 lineno++; 223 switch (line[0]) 224 { 225 case '#': 226 case '\n': 227 case '\0': 228 skipping = FALSE; 229 continue; 230 231 case ' ': 232 case '\t': 233 if (!skipping) 234 syserr("aliases: %d: Non-continuation line starts with space", lineno); 235 skipping = TRUE; 236 continue; 237 } 238 skipping = FALSE; 239 240 /* 241 ** Process the LHS 242 ** Find the final colon, and parse the address. 243 ** It should resolve to a local name -- this will 244 ** be checked later (we want to optionally do 245 ** parsing of the RHS first to maximize error 246 ** detection). 247 */ 248 249 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 250 continue; 251 if (*p == '\0' || *p == '\n') 252 { 253 syntaxerr: 254 syserr("aliases: %d: missing colon", lineno); 255 continue; 256 } 257 *p++ = '\0'; 258 if (parse(line, &al, 1) == NULL) 259 { 260 *--p = ':'; 261 goto syntaxerr; 262 } 263 264 /* 265 ** Process the RHS. 266 ** 'al' is the internal form of the LHS address. 267 ** 'p' points to the text of the RHS. 268 */ 269 270 rhs = p; 271 for (;;) 272 { 273 register char c; 274 275 if (init) 276 { 277 /* do parsing & compression of addresses */ 278 c = *p; 279 while (c != '\0') 280 { 281 p2 = p; 282 while (*p != '\n' && *p != ',' && *p != '\0') 283 p++; 284 c = *p; 285 *p++ = '\0'; 286 if (*p2 == '\0') 287 { 288 p[-1] = c; 289 continue; 290 } 291 (void) parse(p2, &bl, -1); 292 p[-1] = c; 293 while (isspace(*p)) 294 p++; 295 } 296 } 297 else 298 p = &p[strlen(p)]; 299 300 /* see if there should be a continuation line */ 301 c = fgetc(af); 302 if (!feof(af)) 303 (void) ungetc(c, af); 304 if (c != ' ' && c != '\t') 305 break; 306 307 /* read continuation line */ 308 p--; 309 if (fgets(p, sizeof line - (p - line), af) == NULL) 310 break; 311 lineno++; 312 } 313 if (al.q_mailer != MN_LOCAL) 314 { 315 syserr("aliases: %d: cannot alias non-local names", lineno); 316 continue; 317 } 318 319 /* 320 ** Insert alias into symbol table or DBM file 321 */ 322 323 # ifdef DBM 324 if (init) 325 { 326 DATUM key, content; 327 328 key.dsize = strlen(al.q_user) + 1; 329 key.dptr = al.q_user; 330 content.dsize = strlen(rhs) + 1; 331 content.dptr = rhs; 332 store(key, content); 333 } 334 else 335 # endif DBM 336 { 337 s = stab(al.q_user, ST_ALIAS, ST_ENTER); 338 s->s_alias = newstr(rhs); 339 } 340 } 341 (void) fclose(af); 342 } 343 /* 344 ** FORWARD -- Try to forward mail 345 ** 346 ** This is similar but not identical to aliasing. 347 ** 348 ** Parameters: 349 ** user -- the name of the user who's mail we would like 350 ** to forward to. It must have been verified -- 351 ** i.e., the q_home field must have been filled 352 ** in. 353 ** 354 ** Returns: 355 ** none. 356 ** 357 ** Side Effects: 358 ** New names are added to send queues. 359 ** Sets the QDONTSEND bit in addresses that are forwarded. 360 */ 361 362 forward(user) 363 ADDRESS *user; 364 { 365 char buf[60]; 366 struct stat stbuf; 367 368 # ifdef DEBUG 369 if (Debug) 370 printf("forward(%s)\n", user->q_paddr); 371 # endif DEBUG 372 373 if (user->q_mailer != MN_LOCAL || bitset(QBADADDR, user->q_flags)) 374 return; 375 # ifdef DEBUG 376 if (user->q_home == NULL) 377 syserr("forward: no home"); 378 # endif DEBUG 379 380 /* good address -- look for .forward file in home */ 381 define('z', user->q_home); 382 (void) expand("$z/.forward", buf, &buf[sizeof buf - 1]); 383 if (stat(buf, &stbuf) < 0 || stbuf.st_uid != user->q_uid || 384 !bitset(S_IREAD, stbuf.st_mode)) 385 return; 386 387 /* we do have an address to forward to -- do it */ 388 user->q_flags |= QDONTSEND; 389 include(buf, "forwarding"); 390 } 391