/* return 1 if name found in one of the files * 0 if name not found in one of the files * -1 if neither file exists */ extern int lookup(char *cp, char *local, Biobuf **lfpp, char *global, Biobuf **gfpp) { static String *file = 0; if (local) { if (file == 0) file = s_new(); abspath(local, UPASLIB, s_restart(file)); if (*lfpp != 0 || (*lfpp = sysopen(s_to_c(file), "r", 0)) != 0) { if (okfile(cp, *lfpp)) return 1; } else local = 0; } if (global) { abspath(global, UPASLIB, s_restart(file)); if (*gfpp != 0 || (*gfpp = sysopen(s_to_c(file), "r", 0)) != 0) { if (okfile(cp, *gfpp)) return 1; } else global = 0; } return (local || global)? 0 : -1; }
/* * rules are of the form: * <reg exp> <String> <repl exp> [<repl exp>] */ extern int getrules(void) { Biobuf *rfp; String *line; String *type; String *file; file = abspath("rewrite", UPASLIB, (String *)0); rfp = sysopen(s_to_c(file), "r", 0); if(rfp == 0) { rulep = 0; return -1; } rlastp = 0; line = s_new(); type = s_new(); while(s_getline(rfp, s_restart(line))) if(getrule(line, type, thissys) && altthissys) getrule(s_restart(line), type, altthissys); s_free(type); s_free(line); s_free(file); sysclose(rfp); return 0; }
/* parse a mailbox style header */ int parse_header(char *line, String *sender, String *date) { if (!IS_HEADER(line)) return -1; line += sizeof("From ") - 1; s_restart(sender); while(*line==' '||*line=='\t') line++; if(*line == '"'){ s_putc(sender, *line++); while(*line && *line != '"') s_putc(sender, *line++); s_putc(sender, *line++); } else { while(*line && *line != ' ' && *line != '\t') s_putc(sender, *line++); } s_terminate(sender); s_restart(date); while(*line==' '||*line=='\t') line++; while(*line) s_putc(date, *line++); s_terminate(date); return 0; }
static int getrule(String *line, String *type, char *system) { rule *rp; String *re; int backl; backl = 0; /* get a rule */ re = rule_parse(s_restart(line), system, &backl); if(re == 0) return 0; rp = (rule *)malloc(sizeof(rule)); if(rp == 0) { perror("getrules:"); exit(1); } rp->next = 0; s_tolower(re); rp->matchre = s_new(); s_append(rp->matchre, s_to_c(re)); s_restart(rp->matchre); s_free(re); s_parse(line, s_restart(type)); rp->repl1 = rule_parse(line, system, &backl); rp->repl2 = rule_parse(line, system, &backl); rp->program = 0; if(strcmp(s_to_c(type), "|") == 0) rp->type = d_pipe; else if(strcmp(s_to_c(type), ">>") == 0) rp->type = d_cat; else if(strcmp(s_to_c(type), "alias") == 0) rp->type = d_alias; else if(strcmp(s_to_c(type), "translate") == 0) rp->type = d_translate; else if(strcmp(s_to_c(type), "auth") == 0) rp->type = d_auth; else { s_free(rp->matchre); s_free(rp->repl1); s_free(rp->repl2); free((char *)rp); fprint(2,"illegal rewrite rule: %s\n", s_to_c(line)); return 0; } if(rulep == 0) rulep = rlastp = rp; else rlastp = rlastp->next = rp; return backl; }
/* Transforms the address into a command. * Returns: -1 ifaddress not matched by reules * 0 ifaddress matched and ok to forward * 1 ifaddress matched and not ok to forward */ extern int rewrite(dest *dp, message *mp) { rule *rp; /* rewriting rule */ String *lower; /* lower case version of destination */ /* * Rewrite the address. Matching is case insensitive. */ lower = s_clone(dp->addr); s_tolower(s_restart(lower)); rp = findrule(lower, dp->authorized); if(rp == 0){ s_free(lower); return -1; } strcpy(s_to_c(lower), s_to_c(dp->addr)); dp->repl1 = substitute(rp->repl1, rp->subexp, mp); dp->repl2 = substitute(rp->repl2, rp->subexp, mp); dp->status = rp->type; if(debug){ fprint(2, "\t->"); if(dp->repl1) fprint(2, "%s", s_to_c(dp->repl1)); if(dp->repl2) fprint(2, "%s", s_to_c(dp->repl2)); fprint(2, "\n"); } s_free(lower); return 0; }
/* loop through the translation files */ static int translate(char *name, /* name to translate */ char **namev, /* names of this system */ String *files, /* names of system alias files */ String *alias) /* where to put the alias */ { String *file = s_new(); String **fullnamev; int n, rv; rv = -1; DEBUG print("translate(%s, %s, %s)\n", name, s_to_c(files), s_to_c(alias)); /* create the full name to avoid loops (system!name) */ for(n = 0; namev[n]; n++) ; fullnamev = (String**)malloc(sizeof(String*)*(n+2)); n = 0; fullnamev[n++] = s_copy(name); for(; *namev; namev++){ fullnamev[n] = s_copy(*namev); s_append(fullnamev[n], "!"); s_append(fullnamev[n], name); n++; } fullnamev[n] = 0; /* look at system-wide names */ s_restart(files); while (s_parse(files, s_restart(file)) != 0) { if (lookup(fullnamev, file, alias)==0) { rv = 0; goto out; } } out: for(n = 0; fullnamev[n]; n++) s_free(fullnamev[n]); s_free(file); free(fullnamev); return rv; }
int matcher(char *action, Pattern *p, char *message, Resub *m) { char *cp; String *s; for(cp = message; matchpat(p, cp, m); cp = m->ep) { switch(p->action) { case SaveLine: if(vflag) xprint(2, action, m); saveline(linefile, sender, m); break; case HoldHeader: case Hold: if(nflag) continue; if(vflag) xprint(2, action, m); *qdir = holdqueue; if(hflag && qname) { cp = strchr(sender, '!'); if(cp) { *cp = 0; *qname = strdup(sender); *cp = '!'; } else *qname = strdup(sender); } return 1; case Dump: if(vflag) xprint(2, action, m); *(m->ep) = 0; if(!tflag) { s = s_new(); s_append(s, sender); s = unescapespecial(s); syslog(0, "smtpd", "Dumped %s [%s] to %s", s_to_c(s), m->sp, s_to_c(s_restart(recips))); s_free(s); } tflag = 1; if(sflag) cout = opendump(sender); return 1; default: break; } } return 0; }
/* pipe an address through a command to translate it */ extern dest * translate(dest *dp) { process *pp; String *line; dest *rv; char *cp; int n; pp = proc_start(s_to_c(dp->repl1), (stream *)0, outstream(), outstream(), 1, 0); if (pp == 0) { dp->status = d_resource; return 0; } line = s_new(); for(;;) { cp = Brdline(pp->std[1]->fp, '\n'); if(cp == 0) break; if(strncmp(cp, "_nosummary_", 11) == 0){ nosummary = 1; continue; } n = Blinelen(pp->std[1]->fp); cp[n-1] = ' '; s_nappend(line, cp, n); } rv = s_to_dest(s_restart(line), dp); s_restart(line); while(s_read_line(pp->std[2]->fp, line)) ; if ((dp->pstat = proc_wait(pp)) != 0) { dp->repl2 = line; rv = 0; } else s_free(line); proc_free(pp); return rv; }
/* * send the damn thing */ char * data(String *from, Biobuf *b) { char *buf, *cp; int i, n, nbytes, bufsize, eof, r; String *fromline; char errmsg[Errlen]; char id[40]; /* * input the header. */ buf = malloc(1); if(buf == 0){ s_append(s_restart(reply), "out of memory"); return Retry; } n = 0; eof = 0; for(;;){ cp = Brdline(b, '\n'); if(cp == nil){ eof = 1; break; } nbytes = Blinelen(b); buf = realloc(buf, n+nbytes+1); if(buf == 0){ s_append(s_restart(reply), "out of memory"); return Retry; } strncpy(buf+n, cp, nbytes); n += nbytes; if(nbytes == 1) /* end of header */ break; } buf[n] = 0; bufsize = n; /* * parse the header, turn all addresses into @ format */ yyinit(buf, n); yyparse(); /* * print message observing '.' escapes and using \r\n for \n */ alarm(20*alarmscale); if(!filter){ dBprint("DATA\r\n"); switch(getreply()){ case 3: break; case 5: free(buf); return Giveup; default: free(buf); return Retry; } } /* * send header. add a message-id, a sender, and a date if there * isn't one */ nbytes = 0; fromline = convertheader(from); uneaten = buf; srand(truerand()); if(messageid == 0){ for(i=0; i<16; i++){ r = rand()&0xFF; id[2*i] = hex[r&0xF]; id[2*i+1] = hex[(r>>4)&0xF]; } id[2*i] = '\0'; nbytes += Bprint(&bout, "Message-ID: <%s@%s>\r\n", id, hostdomain); if(debug) Bprint(&berr, "Message-ID: <%s@%s>\r\n", id, hostdomain); } if(originator==0){ nbytes += Bprint(&bout, "From: %s\r\n", s_to_c(fromline)); if(debug) Bprint(&berr, "From: %s\r\n", s_to_c(fromline)); } s_free(fromline); if(destination == 0 && toline) if(*s_to_c(toline) == '@'){ /* route addr */ nbytes += Bprint(&bout, "To: <%s>\r\n", s_to_c(toline)); if(debug) Bprint(&berr, "To: <%s>\r\n", s_to_c(toline)); } else { nbytes += Bprint(&bout, "To: %s\r\n", s_to_c(toline)); if(debug) Bprint(&berr, "To: %s\r\n", s_to_c(toline)); } if(date==0 && udate) nbytes += printdate(udate); if (usys) uneaten = usys->end + 1; nbytes += printheader(); if (*uneaten != '\n') putcrnl("\n", 1); /* * send body */ putcrnl(uneaten, buf+n - uneaten); nbytes += buf+n - uneaten; if(eof == 0){ for(;;){ n = Bread(b, buf, bufsize); if(n < 0){ rerrstr(errmsg, sizeof(errmsg)); s_append(s_restart(reply), errmsg); free(buf); return Retry; } if(n == 0) break; alarm(10*alarmscale); putcrnl(buf, n); nbytes += n; } } free(buf); if(!filter){ if(last != '\n') dBprint("\r\n.\r\n"); else dBprint(".\r\n"); alarm(10*alarmscale); switch(getreply()){ case 2: break; case 5: return Giveup; default: return Retry; } syslog(0, "smtp", "%s sent %d bytes to %s", s_to_c(from), nbytes, s_to_c(toline));/**/ } return 0; }
/* read in a message, interpret the 'From' header */ extern message * m_read(Biobuf *fp, int rmail, int interactive) { message *mp; Resub subexp[10]; char *line; int first; int n; mp = m_new(); /* parse From lines if remote */ if (rmail) { /* get remote address */ String *sender=s_new(); if (rfprog == 0) rfprog = regcomp(REMFROMRE); first = 1; while(s_read_line(fp, s_restart(mp->body)) != 0) { memset(subexp, 0, sizeof(subexp)); if (regexec(rfprog, s_to_c(mp->body), subexp, 10) == 0){ if(first == 0) break; if (fprog == 0) fprog = regcomp(FROMRE); memset(subexp, 0, sizeof(subexp)); if(regexec(fprog, s_to_c(mp->body), subexp,10) == 0) break; s_restart(mp->body); append_match(subexp, s_restart(sender), SENDERMATCH); append_match(subexp, s_restart(mp->date), DATEMATCH); break; } append_match(subexp, s_restart(sender), REMSENDERMATCH); append_match(subexp, s_restart(mp->date), REMDATEMATCH); if(subexp[REMSYSMATCH].sp!=subexp[REMSYSMATCH].ep){ append_match(subexp, mp->sender, REMSYSMATCH); s_append(mp->sender, "!"); } first = 0; } s_append(mp->sender, s_to_c(sender)); s_free(sender); } if(*s_to_c(mp->sender)=='\0') default_from(mp); /* if sender address is unreturnable, treat message as bulk mail */ if(!returnable(s_to_c(mp->sender))) mp->bulk = 1; /* get body */ if(interactive && !rmail){ /* user typing on terminal: terminator == '.' or EOF */ for(;;) { line = s_read_line(fp, mp->body); if (line == 0) break; if (strcmp(".\n", line)==0) { mp->body->ptr -= 2; *mp->body->ptr = '\0'; break; } } mp->size = mp->body->ptr - mp->body->base; } else { /* * read up to VMLIMIT bytes (more or less) into main memory. * if message is longer put the rest in a tmp file. */ mp->size = mp->body->ptr - mp->body->base; n = s_read(fp, mp->body, VMLIMIT); if(n < 0){ perror("m_read"); exit(1); } mp->size += n; if(n == VMLIMIT){ if(m_read_to_file(fp, mp) < 0){ perror("m_read"); exit(1); } } } /* * ignore 0 length messages from a terminal */ if (!rmail && mp->size == 0) return 0; rfc822cruft(mp); return mp; }
/* Loop through the entries in a translation file looking for a match. * Return 0 if found, -1 otherwise. */ static int lookup( String **namev, String *file, String *alias) /* returned String */ { String *line = s_new(); String *token = s_new(); String *bangtoken; int i, rv = -1; char *name = s_to_c(namev[0]); Sinstack *sp; DEBUG print("lookup(%s, %s, %s, %s)\n", s_to_c(namev[0]), s_to_c(namev[1]), s_to_c(file), s_to_c(alias)); s_reset(alias); if ((sp = s_allocinstack(s_to_c(file))) == 0) return -1; /* look for a match */ while (s_rdinstack(sp, s_restart(line))!=0) { DEBUG print("line is %s\n", s_to_c(line)); s_restart(token); if (s_parse(s_restart(line), token)==0) continue; if (compare(token, "#include")==0){ if(s_parse(line, s_restart(token))!=0) { if(lookup(namev, line, alias) == 0) break; } continue; } if (compare(token, name)!=0) continue; /* match found, get the alias */ while(s_parse(line, s_restart(token))!=0) { bangtoken = attobang(token); /* avoid definition loops */ for(i = 0; namev[i]; i++) if(compare(bangtoken, s_to_c(namev[i]))==0) { s_append(alias, "local"); s_append(alias, "!"); s_append(alias, name); break; } if(namev[i] == 0) s_append(alias, s_to_c(token)); s_append(alias, "\n"); if(bangtoken != token) s_free(bangtoken); } rv = 0; break; } s_free(line); s_free(token); s_freeinstack(sp); return rv; }
static String * substitute(String *source, Resub *subexp, message *mp) { int i; char *s; char *sp; String *stp; if(source == 0) return 0; sp = s_to_c(source); /* someplace to put it */ stp = s_new(); /* do the substitution */ while (*sp != '\0') { if(*sp == '\\') { switch (*++sp) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i = *sp-'0'; if(subexp[i].s.sp != 0) for (s = subexp[i].s.sp; s < subexp[i].e.ep; s++) s_putc(stp, *s); break; case '\\': s_putc(stp, '\\'); break; case '\0': sp--; break; case 's': for(s = s_to_c(mp->replyaddr); *s; s++) s_putc(stp, *s); break; case 'p': if(mp->bulk) s = "bulk"; else s = "normal"; for(;*s; s++) s_putc(stp, *s); break; default: s_putc(stp, *sp); break; } } else if(*sp == '&') { if(subexp[0].s.sp != 0) for (s = subexp[0].s.sp; s < subexp[0].e.ep; s++) s_putc(stp, *s); } else if(*sp == '$') { sp = getrcvar(sp+1, &s); s_append(stp, s); free(s); sp--; /* counter sp++ below */ } else s_putc(stp, *sp); sp++; } s_terminate(stp); return s_restart(stp); }