1 # include <stdio.h> 2 # include <ctype.h> 3 # include <pwd.h> 4 # include "sendmail.h" 5 6 # ifdef DBM 7 static char SccsId[] = "@(#)alias.c 3.13 08/18/81 (with DBM)"; 8 # else DBM 9 static char SccsId[] = "@(#)alias.c 3.13 08/18/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 # ifdef DBM 82 /* create a key for fetch */ 83 lhs.dptr = a->q_user; 84 lhs.dsize = strlen(a->q_user) + 1; 85 rhs = fetch(lhs); 86 87 /* find this alias? */ 88 p = rhs.dptr; 89 if (p == NULL) 90 return; 91 # else DBM 92 s = stab(a->q_user, ST_ALIAS, ST_FIND); 93 if (s == NULL) 94 return; 95 p = s->s_alias; 96 # endif DBM 97 98 /* 99 ** Match on Alias. 100 ** Deliver to the target list. 101 */ 102 103 # ifdef DEBUG 104 if (Debug) 105 printf("%s (%s, %s) aliased to %s\n", 106 a->q_paddr, a->q_host, a->q_user, p); 107 # endif 108 if (Verbose) 109 message("050", "aliased to %s", p); 110 a->q_flags |= QDONTSEND; 111 AliasLevel++; 112 sendto(p, 1); 113 AliasLevel--; 114 } 115 /* 116 ** INITALIASES -- initialize for aliasing 117 ** 118 ** Very different depending on whether we are running DBM or not. 119 ** 120 ** Parameters: 121 ** aliasfile -- location of aliases. 122 ** init -- if set and if DBM, initialize the DBM files. 123 ** 124 ** Returns: 125 ** none. 126 ** 127 ** Side Effects: 128 ** initializes aliases: 129 ** if DBM: opens the database. 130 ** if ~DBM: reads the aliases into the symbol table. 131 */ 132 133 # define DBMMODE 0666 134 135 initaliases(aliasfile, init) 136 char *aliasfile; 137 bool init; 138 { 139 # ifdef DBM 140 if (init) 141 { 142 char buf[MAXNAME]; 143 144 (void) strcpy(buf, aliasfile); 145 (void) strcat(buf, ".dir"); 146 if (close(creat(buf, DBMMODE)) < 0) 147 { 148 syserr("cannot make %s", buf); 149 return; 150 } 151 (void) strcpy(buf, aliasfile); 152 (void) strcat(buf, ".pag"); 153 if (close(creat(buf, DBMMODE)) < 0) 154 { 155 syserr("cannot make %s", buf); 156 return; 157 } 158 } 159 dbminit(aliasfile); 160 if (init) 161 readaliases(aliasfile, TRUE); 162 # else DBM 163 readaliases(aliasfile, init); 164 # endif DBM 165 } 166 /* 167 ** READALIASES -- read and process the alias file. 168 ** 169 ** This routine implements the part of initaliases that occurs 170 ** when we are not going to use the DBM stuff. 171 ** 172 ** Parameters: 173 ** aliasfile -- the pathname of the alias file master. 174 ** init -- if set, initialize the DBM stuff. 175 ** 176 ** Returns: 177 ** none. 178 ** 179 ** Side Effects: 180 ** Reads aliasfile into the symbol table. 181 ** Optionally, builds the .dir & .pag files. 182 */ 183 184 static 185 readaliases(aliasfile, init) 186 char *aliasfile; 187 bool init; 188 { 189 char line[BUFSIZ]; 190 register char *p; 191 char *p2; 192 char *rhs; 193 bool skipping; 194 ADDRESS al, bl; 195 FILE *af; 196 int lineno; 197 register STAB *s; 198 199 if ((af = fopen(aliasfile, "r")) == NULL) 200 { 201 # ifdef DEBUG 202 if (Debug) 203 printf("Can't open %s\n", aliasfile); 204 # endif 205 errno = 0; 206 NoAlias++; 207 return; 208 } 209 /* read and interpret lines */ 210 lineno = 0; 211 skipping = FALSE; 212 while (fgets(line, sizeof (line), af) != NULL) 213 { 214 lineno++; 215 switch (line[0]) 216 { 217 case '#': 218 case '\n': 219 case '\0': 220 skipping = FALSE; 221 continue; 222 223 case ' ': 224 case '\t': 225 if (!skipping) 226 syserr("aliases: %d: Non-continuation line starts with space", lineno); 227 skipping = TRUE; 228 continue; 229 } 230 skipping = FALSE; 231 232 /* process the LHS */ 233 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 234 continue; 235 if (*p == '\0' || *p == '\n') 236 { 237 syntaxerr: 238 syserr("aliases: %d: missing colon", lineno); 239 continue; 240 } 241 *p++ = '\0'; 242 if (parse(line, &al, 1) == NULL) 243 { 244 *--p = ':'; 245 goto syntaxerr; 246 } 247 rhs = p; 248 for (;;) 249 { 250 register char c; 251 252 if (init) 253 { 254 /* do parsing & compression of addresses */ 255 c = *p; 256 while (c != '\0') 257 { 258 p2 = p; 259 while (*p != '\n' && *p != ',' && *p != '\0') 260 p++; 261 c = *p; 262 *p++ = '\0'; 263 if (*p2 == '\0') 264 { 265 p[-1] = c; 266 continue; 267 } 268 parse(p2, &bl, -1); 269 p[-1] = c; 270 while (isspace(*p)) 271 p++; 272 } 273 } 274 else 275 p = &p[strlen(p)]; 276 277 /* see if there should be a continuation line */ 278 c = fgetc(af); 279 if (!feof(af)) 280 ungetc(c, af); 281 if (c != ' ' && c != '\t') 282 break; 283 284 /* read continuation line */ 285 p--; 286 if (fgets(p, sizeof line - (p - line), af) == NULL) 287 break; 288 lineno++; 289 } 290 if (al.q_mailer != M_LOCAL) 291 { 292 syserr("aliases: %d: cannot alias non-local names", lineno); 293 continue; 294 } 295 # ifdef DBM 296 if (init) 297 { 298 DATUM key, content; 299 300 key.dsize = strlen(al.q_user) + 1; 301 key.dptr = al.q_user; 302 content.dsize = strlen(rhs) + 1; 303 content.dptr = rhs; 304 store(key, content); 305 } 306 else 307 # endif DBM 308 { 309 s = stab(al.q_user, ST_ALIAS, ST_ENTER); 310 s->s_alias = newstr(rhs); 311 } 312 } 313 (void) fclose(af); 314 } 315 /* 316 ** FORWARD -- Try to forward mail 317 ** 318 ** This is similar but not identical to aliasing. 319 ** 320 ** Parameters: 321 ** user -- the name of the user who's mail we 322 ** would like to forward to. 323 ** 324 ** Returns: 325 ** none. 326 ** 327 ** Side Effects: 328 ** New names are added to send queues. 329 ** Sets the QDONTSEND bit in addresses that are forwarded. 330 */ 331 332 forward(user) 333 ADDRESS *user; 334 { 335 char buf[60]; 336 register FILE *fp; 337 register char *p; 338 339 # ifdef DEBUG 340 if (Debug) 341 printf("forward(%s)\n", user->q_paddr); 342 # endif DEBUG 343 344 if (user->q_mailer != M_LOCAL || bitset(QBADADDR, user->q_flags)) 345 return; 346 347 /* good address -- look for .forward file in home */ 348 define('z', user->q_home); 349 (void) expand("$z/.forward", buf, &buf[sizeof buf - 1]); 350 fp = fopen(buf, "r"); 351 if (fp == NULL) 352 return; 353 354 /* we do have an address to forward to -- do it */ 355 user->q_flags |= QDONTSEND; 356 (void) fgets(buf, sizeof buf, fp); 357 if ((p = index(buf, '\n')) != NULL) 358 *p = '\0'; 359 (void) fclose(fp); 360 if (buf[0] == '\0') 361 return; 362 if (Verbose) 363 message("050", "forwarded to %s", buf); 364 AliasLevel++; 365 sendto(buf, 1); 366 AliasLevel--; 367 return; 368 } 369