18 typedef struct Keyword Keyword;
25 static Keyword options[] = {
27 "verifysenderdom", DNSVERIFY,
28 "saveblockedmsg", SAVEBLOCK,
29 "defaultdomain", DOMNAME,
31 "ourdomains", OURDOMS,
35 static Keyword actions[] = {
47 static ulong v4peerip;
49 static char* getline(Biobuf*);
50 static int cidrcheck(char*);
53 findkey(char *val, Keyword *p)
57 if(strcmp(val, p->name) == 0)
68 for(p=actions; p->name; p++)
78 getaction(char *s, char *type)
83 if(s == nil || *s == 0)
86 for(k = actions; k->name != 0; k++){
87 snprint(buf, sizeof buf, "/mail/ratify/%s/%s/%s", k->name, type, s);
88 if(access(buf,0) >= 0)
99 if(s == nil || *s == 0)
102 snprint(buf, sizeof buf, "/mail/ratify/trusted/%s", s);
103 return access(buf,0) >= 0;
115 v4parseip(addr, nci->rsys);
116 v4peerip = nhgetl(addr);
118 trusted = istrusted(nci->rsys);
119 hisaction = getaction(nci->rsys, "ip");
121 fprint(2, "istrusted(%s)=%d\n", nci->rsys, trusted);
122 fprint(2, "getaction(%s, ip)=%s\n", nci->rsys, actstr(hisaction));
124 snprint(buf, sizeof(buf), "%s/smtpd.conf", UPASLIB);
125 bp = sysopen(buf, "r", 0);
134 switch(findkey(cp, options)){
136 if(fflag == 0 && strcmp(p, "on") == 0)
140 if(rflag == 0 && strcmp(p, "on") == 0)
144 if(sflag == 0 && strcmp(p, "on") == 0)
153 trusted = cidrcheck(p);
159 listadd(&ourdoms, s);
171 * match a user name. the only meta-char is '*' which matches all
172 * characters. we only allow it as "*", which matches anything or
173 * an * at the end of the name (e.g., "username*") which matches
174 * trailing characters.
177 usermatch(char *pathuser, char *specuser)
181 n = strlen(specuser)-1;
182 if(specuser[n] == '*'){
183 if(n == 0) /* match everything */
185 return strncmp(pathuser, specuser, n);
187 return strcmp(pathuser, specuser);
191 dommatch(char *pathdom, char *specdom)
195 if (*specdom == '*'){
196 if (specdom[1] == '.' && specdom[2]){
198 n = strlen(pathdom)-strlen(specdom);
199 if(n == 0 || (n > 0 && pathdom[n-1] == '.'))
200 return strcmp(pathdom+n, specdom);
204 return strcmp(pathdom, specdom);
208 * figure out action for this sender
211 blocked(String *path)
217 fprint(2, "blocked(%s)\n", s_to_c(path));
219 /* if the sender's IP address is blessed, ignore sender email address */
222 fprint(2, "\ttrusted => trusted\n");
226 /* if sender's IP address is blocked, ignore sender email address */
227 if(hisaction != ACCEPT){
229 fprint(2, "\thisaction=%s => %s\n", actstr(hisaction), actstr(hisaction));
233 /* convert to lower case */
234 lpath = s_copy(s_to_c(path));
238 action = getaction(s_to_c(lpath), "account");
240 fprint(2, "\tgetaction account %s => %s\n", s_to_c(lpath), actstr(action));
246 * get a canonicalized line: a string of null-terminated lower-case
247 * tokens with a two null bytes at the end.
259 cp = Brdline(bp, '\n');
264 if(buf == 0 || bufsize < n+1){
268 buf = realloc(buf, bufsize);
273 for (p = cp; *p; p++){
275 if(c == '\\' && p[1]) /* we don't allow \<newline> */
281 if(c == ' ' || c == '\t' || c == ',')
282 if(q == buf || q[-1] == 0)
303 if(strchr(s, '.') == nil)
306 for(l = ourdoms.first; l; l = l->next){
307 if(dommatch(s, s_to_c(l->p)) == 0)
314 forwarding(String *path)
320 fprint(2, "forwarding(%s)\n", s_to_c(path));
322 /* first check if they want loopback */
323 lpath = s_copy(s_to_c(s_restart(path)));
324 if(nci->rsys && *nci->rsys){
326 if(strncmp(cp, "[]!", 3) == 0){
329 s_append(path, nci->rsys);
330 s_append(path, "]!");
331 s_append(path, cp+3);
336 cp = strchr(cp,'!'); /* skip our domain and check next */
337 if(cp++ && strncmp(cp, "[]!", 3) == 0)
341 /* if mail is from a trusted IP addr, allow it to forward */
347 /* sender is untrusted; ensure receiver is in one of our domains */
348 for(cp = s_to_c(lpath); *cp; cp++) /* convert receiver lc */
351 for(s = s_to_c(lpath); cp = strchr(s, '!'); s = cp+1){
363 masquerade(String *path, char *him)
370 fprint(2, "masquerade(%s)\n", s_to_c(path));
377 lpath = s_copy(s_to_c(path));
379 /* sender is untrusted; ensure receiver is in one of our domains */
380 for(cp = s_to_c(lpath); *cp; cp++) /* convert receiver lc */
384 /* scan first element of ! or last element of @ paths */
385 if((cp = strchr(s, '!')) != nil){
389 } else if((cp = strrchr(s, '@')) != nil){
401 /* this is a v4 only check */
407 uchar addr[IPv4addrlen];
408 uchar mask[IPv4addrlen];
413 /* parse a list of CIDR addresses comparing each to the peer IP addr */
415 v4parsecidr(addr, mask, cp);
419 * if a mask isn't specified, we build a minimal mask
420 * instead of using the default mask for that net. in this
421 * case we never allow a class A mask (0xff000000).
423 if(strchr(cp, '/') == 0){
426 for(p = strchr(p, '.'); p && p[1]; p = strchr(p+1, '.'))
427 m = (m>>8)|0xff000000;
429 /* force at least a class B */
432 if((v4peerip&m) == a)
444 /* check if this IP address is banned */
445 for(l = badguys.first; l; l = l->next)
446 if(cidrcheck(s_to_c(l->p)))
455 listadd(&badguys, s_copy(p));
459 dumpfile(char *sender)
463 static char buf[512];
470 sprint(buf, "%s/queue.dump/%s%c", SPOOL, cp+4, cp[9]);
472 sprint(buf, "%s/queue.dump/%s%c%c", SPOOL, cp+4, cp[8], cp[9]);
473 cp = buf+strlen(buf);
474 if(access(buf, 0) < 0 && sysmkdir(buf, 0777) < 0)
478 h = h*257 + *sender++;
479 for(i = 0; i < 50; i++){
481 sprint(cp, "/%lud", h);
482 if(access(buf, 0) >= 0)
484 fd = syscreate(buf, ORDWR, 0666);
487 fprint(2, "saving in %s\n", buf);
496 char *validator = "/mail/lib/validateaddress";
508 if(shellchars(user)){
509 syslog(0, "smtpd", "shellchars in user name");
513 if(access(validator, AEXEC) == 0)
514 switch(pid = fork()) {
518 execl(validator, "validateaddress", user, nil);
526 syslog(0, "smtpd", "validateaddress %s: %s", user, w->msg);
534 snprint(buf, sizeof(buf), "%s/names.blocked", UPASLIB);
535 bp = sysopen(buf, "r", 0);
539 cp = Brdline(bp, '\n');
545 while(*cp == ' ' || *cp == '\t')
547 for(p = cp; c = *p; p++){
550 if(c == ' ' || c == '\t')
555 if(cistrcmp(user, cp) == 0){
556 syslog(0, "smtpd", "names.blocked blocks %s", user);
567 * a user can opt out of spam filtering by creating
568 * a file in his mail directory named 'nospamfiltering'.
571 optoutofspamfilter(char *addr)
576 p = strchr(addr, '!');
584 f = smprint("/mail/box/%s/nospamfiltering", p);
586 rv = access(f, 0)==0;