static int isclean(char *addr, int flagaddr) /* 1 for addresses with '@', 0 for other args */ /* assures that addr has only letters, digits, "-_" */ /* also checks allows single '@' if flagaddr = 1 */ /* returns 1 if clean, 0 otherwise */ { unsigned int pos; char ch; char *cp; if (flagaddr) { /* shoud have one '@' */ pos = str_chr(addr,'@'); if (!pos || !addr[pos]) return 0; /* at least 1 char for local */ if (!addr[pos+1]) return 0; /* host must be at least 1 char */ pos++; case_lowerb(addr+pos,str_len(addr)-pos); } else pos = 0; pos += str_chr(addr + pos,'@'); if (addr[pos]) /* but no more */ return 0; cp = addr; while ((ch = *(cp++))) if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch >= '0' && ch <= '9') && ch != '.' && ch != '-' && ch != '_' && ch != '@') return 0; return 1; }
static int doit(char *q,char qtype[2],char ip[4]) { int r; uint32 dlen; unsigned int qlen; qlen = dns_domain_length(q); if (qlen > 255) return 0; /* impossible */ if (byte_diff(qtype,2,DNS_T_A) && byte_diff(qtype,2,DNS_T_ANY)) goto REFUSE; key[0] = '%'; byte_copy(key + 1,4,ip); r = cdb_find(&c,key,5); if (!r) r = cdb_find(&c,key,4); if (!r) r = cdb_find(&c,key,3); if (!r) r = cdb_find(&c,key,2); if (r == -1) return 0; key[0] = '+'; byte_zero(key + 1,2); if (r && (cdb_datalen(&c) == 2)) if (cdb_read(&c,key + 1,2,cdb_datapos(&c)) == -1) return 0; byte_copy(key + 3,qlen,q); case_lowerb(key + 3,qlen + 3); r = cdb_find(&c,key,qlen + 3); if (!r) { byte_zero(key + 1,2); r = cdb_find(&c,key,qlen + 3); } if (!r) goto REFUSE; if (r == -1) return 0; dlen = cdb_datalen(&c); if (dlen > 512) dlen = 512; if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) return 0; dns_sortip(data,dlen); if (dlen > 12) dlen = 12; while (dlen >= 4) { dlen -= 4; if (!response_rstart(q,DNS_T_A,"\0\0\0\5")) return 0; if (!response_addbytes(data + dlen,4)) return 0; response_rfinish(RESPONSE_ANSWER); } return 1; REFUSE: response[2] &= ~4; response[3] &= ~15; response[3] |= 5; return 1; }
void rr_finish(const char *owner) { if (byte_equal(owner,2,"\1*")) { owner += 2; result.s[2] -= 19; } if (!stralloc_copyb(&key,owner,dns_domain_length(owner))) nomem(); case_lowerb(key.s,key.len); if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1) die_datatmp(); }
static int doit(void) { unsigned int pos; char header[12]; char qtype[2]; char qclass[2]; if (len >= sizeof buf) goto NOQ; pos = dns_packet_copy(buf,len,0,header,12); if (!pos) goto NOQ; if (header[2] & 128) goto NOQ; if (header[4]) goto NOQ; if (header[5] != 1) goto NOQ; pos = dns_packet_getname(buf,len,pos,&q); if (!pos) goto NOQ; pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) goto NOQ; pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) goto NOQ; if (!response_query(q,qtype,qclass)) goto NOQ; response_id(header); if (byte_equal(qclass,2,DNS_C_IN)) response[2] |= 4; else if (byte_diff(qclass,2,DNS_C_ANY)) goto WEIRDCLASS; response[3] &= ~128; if (!(header[2] & 1)) response[2] &= ~1; if (header[2] & 126) goto NOTIMP; if (byte_equal(qtype,2,DNS_T_AXFR)) goto NOTIMP; case_lowerb(q,dns_domain_length(q)); if (!respond(q,qtype,ip)) { qlog(ip,port,header,q,qtype," - "); return 0; } qlog(ip,port,header,q,qtype," + "); return 1; NOTIMP: response[3] &= ~15; response[3] |= 4; qlog(ip,port,header,q,qtype," I "); return 1; WEIRDCLASS: response[3] &= ~15; response[3] |= 1; qlog(ip,port,header,q,qtype," C "); return 1; NOQ: qlog(ip,port,"\0\0","","\0\0"," / "); return 0; }
static int _issub(struct subdbinfo *info, const char *table, const char *userhost, stralloc *recorded) { sqlite3_stmt *stmt; unsigned int j; int res; /* SELECT address FROM list WHERE address = 'userhost' AND hash */ /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */ /* even easier to defeat. Just faking sender to the list name would*/ /* work. Since sender checks for posts are bogus anyway, I don't */ /* know if it's worth the cost of the "WHERE ...". */ if (!stralloc_copys(&addr,userhost)) die_nomem(); j = byte_rchr(addr.s,addr.len,'@'); if (j == addr.len) return 0; case_lowerb(addr.s + j + 1,addr.len - j - 1); if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(); if (!stralloc_cat_table(&line,info,table)) die_nomem(); if (!stralloc_cats(&line," WHERE address LIKE '")) die_nomem(); if (!stralloc_cat(&line,&addr)) die_nomem(); if (!stralloc_cats(&line,"'")) die_nomem(); if (!stralloc_0(&line)) die_nomem(); if ((stmt = _sqlquery(info, &line)) == NULL) /* select */ strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn)); /* No data returned in QUERY */ res = sqlite3_step(stmt); if (res != SQLITE_ROW) { if (res != SQLITE_DONE) strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn)); sqlite3_finalize(stmt); return 0; } if (recorded) { if (!stralloc_copyb(recorded, (const char*)sqlite3_column_text(stmt, 0), sqlite3_column_bytes(stmt, 0))) die_nomem(); if (!stralloc_0(recorded)) die_nomem(); } sqlite3_finalize(stmt); return 1; }
int sub_sql_issub(struct subdbinfo *info, const char *table, const char *userhost, stralloc *recorded) { unsigned int j; void *result; int ret; /* SELECT address FROM list WHERE address = 'userhost' AND hash */ /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */ /* even easier to defeat. Just faking sender to the list name would*/ /* work. Since sender checks for posts are bogus anyway, I don't */ /* know if it's worth the cost of the "WHERE ...". */ make_name(info,table?"_":0,table,0); /* Lower-case the domain portion */ stralloc_copys(&addr,userhost); j = byte_rchr(addr.s,addr.len,'@'); if (j == addr.len) return 0; case_lowerb(addr.s + j + 1,addr.len - j - 1); stralloc_copys(&query,"SELECT address FROM "); stralloc_cat(&query,&name); stralloc_cats(&query," WHERE "); stralloc_cats(&query,sql_issub_where_defn); result = sql_select(info,&query,1,&addr); if (!sql_fetch_row(info,result,1,&addr)) ret = 0; else { /* we need to return the actual address as other dbs may accept * user-*@host, but we still want to make sure to send to e.g the * correct moderator address. */ if (recorded != 0) { stralloc_copy(recorded,&addr); stralloc_0(recorded); } ret = 1; } sql_free_result(info,result); return ret; }
void rr_finish (const char *owner) { if (byte_equal (owner, 2, "\1*")) { owner += 2; result.s[2] -= 19; } if (!stralloc_copyb (&key, owner, dns_domain_length (owner))) err (-1, "could not allocate enough memory"); case_lowerb (key.s, key.len); if (cdb_make_add (&cdb, key.s, key.len, result.s, result.len) == -1) errx (-1, "could not create file `data.tmp'"); }
int main(int argc,char **argv) { uint16 u16; if (!*argv) usage(); if (!*++argv) usage(); if (!parsetype(*argv,type)) usage(); if (!*++argv) usage(); if (!dns_domain_fromdot(&q,*argv,str_len(*argv))) oops(); if (*++argv) { if (!ip4_scan(*argv,ip)) usage(); } if (!stralloc_copys(&out,"")) oops(); /* uint16_unpack_big(type,&u16); if (!stralloc_catulong0(&out,u16,0)) oops(); if (!stralloc_cats(&out," ")) oops(); if (!dns_domain_todot_cat(&out,q)) oops(); if (!stralloc_cats(&out,":\n")) oops(); */ if (!response_query(q,type,DNS_C_IN)) oops(); response[3] &= ~128; response[2] &= ~1; response[2] |= 4; case_lowerb(q,dns_domain_length(q)); if (byte_equal(type,2,DNS_T_AXFR)) { response[3] &= ~15; response[3] |= 4; } else if (!respond(q,type,ip)) goto DONE; if (!printpacket_cat(&out,response,response_len)) oops(); DONE: buffer_putflush(buffer_1,out.s,out.len); _exit(0); }
int main() { umask(033); if (chdir(auto_qmail) == -1) strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": "); fd = open_read("control/morercpthosts"); if (fd == -1) die_read(); substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf); fdtemp = open_trunc("control/morercpthosts.tmp"); if (fdtemp == -1) die_write(); if (cdbmss_start(&cdbmss,fdtemp) == -1) die_write(); for (;;) { if (getln(&ssin,&line,&match,'\n') != 0) die_read(); case_lowerb(line.s,line.len); while (line.len) { if (line.s[line.len - 1] == ' ') { --line.len; continue; } if (line.s[line.len - 1] == '\n') { --line.len; continue; } if (line.s[line.len - 1] == '\t') { --line.len; continue; } if (line.s[0] != '#') if (cdbmss_add(&cdbmss,line.s,line.len,"",0) == -1) die_write(); break; } if (!match) break; } if (cdbmss_finish(&cdbmss) == -1) die_write(); if (fsync(fdtemp) == -1) die_write(); if (close(fdtemp) == -1) die_write(); /* NFS stupidity */ if (rename("control/morercpthosts.tmp","control/morercpthosts.cdb") == -1) strerr_die2sys(111,FATAL,"unable to move control/morercpthosts.tmp to control/morercpthosts.cdb"); _exit(0); }
int main(int argc, char **argv) { umask(033); if (argc != 3) strerr_die1sys(111,"qmail-cdb: usage: qmail-cdb rules.cdb rules.tmp"); substdio_fdbuf(&ssin,subread,0,inbuf,sizeof inbuf); fdtemp = open_trunc(argv[2]); if (fdtemp == -1) die_write(argv[2]); if (cdb_make_start(&cdbm,fdtemp) == -1) die_write(argv[2]); for (;;) { if (getln(&ssin,&line,&match,'\n') != 0) die_read(); case_lowerb(line.s,line.len); while (line.len) { if (line.s[line.len - 1] == ' ') { --line.len; continue; } if (line.s[line.len - 1] == '\n') { --line.len; continue; } if (line.s[line.len - 1] == '\t') { --line.len; continue; } if (line.s[0] != '#') if (cdb_make_add(&cdbm,line.s,line.len,"",0) == -1) die_write(argv[2]); break; } if (!match) break; } if (cdb_make_finish(&cdbm) == -1) die_write(argv[2]); if (fsync(fdtemp) == -1) die_write(argv[2]); if (close(fdtemp) == -1) die_write(argv[2]); /* NFS stupidity */ if (rename(argv[2],argv[1]) == -1) strerr_die5sys(111, FATAL, "unable to move ", argv[2], " to ", argv[1]); return 0; }
static int doit(char *q,char qtype[2]) { unsigned int bpos; unsigned int anpos; unsigned int aupos; unsigned int arpos; char *control; char *wild; int flaggavesoa; int flagfound; int r; int flagns; int flagauthoritative; char x[20]; uint16 u16; char addr[8][4]; int addrnum; uint32 addrttl; int i; anpos = response_len; control = q; for (;;) { flagns = 0; flagauthoritative = 0; cdb_findstart(&c); while (r = find(control,0)) { if (r == -1) return 0; if (byte_equal(type,2,DNS_T_SOA)) flagauthoritative = 1; if (byte_equal(type,2,DNS_T_NS)) flagns = 1; } if (flagns) break; if (!*control) return 0; /* q is not within our bailiwick */ control += *control; control += 1; } if (!flagauthoritative) { response[2] &= ~4; goto AUTHORITY; /* q is in a child zone */ } flaggavesoa = 0; flagfound = 0; wild = q; for (;;) { addrnum = 0; addrttl = 0; cdb_findstart(&c); while (r = find(wild,wild != q)) { if (r == -1) return 0; flagfound = 1; if (flaggavesoa && byte_equal(type,2,DNS_T_SOA)) continue; if (byte_diff(type,2,qtype) && byte_diff(qtype,2,DNS_T_ANY) && byte_diff(type,2,DNS_T_CNAME)) continue; if (byte_equal(type,2,DNS_T_A) && (dlen - dpos == 4)) { addrttl = ttl; i = dns_random(addrnum + 1); if (i < 8) { if ((i < addrnum) && (addrnum < 8)) byte_copy(addr[addrnum],4,addr[i]); byte_copy(addr[i],4,data + dpos); } if (addrnum < 1000000) ++addrnum; continue; } if (!response_rstart(q,type,ttl)) return 0; if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_CNAME) || byte_equal(type,2,DNS_T_PTR)) { if (!doname()) return 0; } else if (byte_equal(type,2,DNS_T_MX)) { if (!dobytes(2)) return 0; if (!doname()) return 0; } else if (byte_equal(type,2,DNS_T_SOA)) { if (!doname()) return 0; if (!doname()) return 0; if (!dobytes(20)) return 0; flaggavesoa = 1; } else if (!response_addbytes(data + dpos,dlen - dpos)) return 0; response_rfinish(RESPONSE_ANSWER); } for (i = 0;i < addrnum;++i) if (i < 8) { if (!response_rstart(q,DNS_T_A,addrttl)) return 0; if (!response_addbytes(addr[i],4)) return 0; response_rfinish(RESPONSE_ANSWER); } if (flagfound) break; if (wild == control) break; if (!*wild) break; /* impossible */ wild += *wild; wild += 1; } if (!flagfound) response_nxdomain(); AUTHORITY: aupos = response_len; if (flagauthoritative && (aupos == anpos)) { cdb_findstart(&c); while (r = find(control,0)) { if (r == -1) return 0; if (byte_equal(type,2,DNS_T_SOA)) { if (!response_rstart(control,DNS_T_SOA,ttl)) return 0; if (!doname()) return 0; if (!doname()) return 0; if (!dobytes(20)) return 0; response_rfinish(RESPONSE_AUTHORITY); break; } } } else if (want(control,DNS_T_NS)) { cdb_findstart(&c); while (r = find(control,0)) { if (r == -1) return 0; if (byte_equal(type,2,DNS_T_NS)) { if (!response_rstart(control,DNS_T_NS,ttl)) return 0; if (!doname()) return 0; response_rfinish(RESPONSE_AUTHORITY); } } } arpos = response_len; bpos = anpos; while (bpos < arpos) { bpos = dns_packet_skipname(response,arpos,bpos); if (!bpos) return 0; bpos = dns_packet_copy(response,arpos,bpos,x,10); if (!bpos) return 0; if (byte_equal(x,2,DNS_T_NS) || byte_equal(x,2,DNS_T_MX)) { if (byte_equal(x,2,DNS_T_NS)) { if (!dns_packet_getname(response,arpos,bpos,&d1)) return 0; } else if (!dns_packet_getname(response,arpos,bpos + 2,&d1)) return 0; case_lowerb(d1,dns_domain_length(d1)); if (want(d1,DNS_T_A)) { cdb_findstart(&c); while (r = find(d1,0)) { if (r == -1) return 0; if (byte_equal(type,2,DNS_T_A)) { if (!response_rstart(d1,DNS_T_A,ttl)) return 0; if (!dobytes(4)) return 0; response_rfinish(RESPONSE_ADDITIONAL); } } } } uint16_unpack_big(x + 8,&u16); bpos += u16; } if (flagauthoritative && (response_len > 512)) { byte_zero(response + RESPONSE_ADDITIONAL,2); response_len = arpos; if (response_len > 512) { byte_zero(response + RESPONSE_AUTHORITY,2); response_len = aupos; } } return 1; }
int lookup_cdb(const char *mail) { int fd; int flagwild; int r; if (!stralloc_copys(&lower, "!")) die_nomem(); if (!stralloc_cats(&lower, mail)) die_nomem(); if (!stralloc_0(&lower)) die_nomem(); case_lowerb(lower.s, lower.len); fd = open_read("users/cdb"); if (fd == -1) if (errno != error_noent) die_cdb(); if (fd != -1) { uint32 dlen; unsigned int i; cdb_init(&cdb, fd); r = cdb_seek(&cdb, "", 0, &dlen); if (r != 1) die_cdb(); if (!stralloc_ready(&wildchars, (unsigned int) dlen)) die_nomem(); wildchars.len = dlen; if (cdb_bread(&cdb, wildchars.s, wildchars.len) == -1) die_cdb(); i = lower.len; flagwild = 0; do { /* i > 0 */ if (!flagwild || i == 1 || byte_chr(wildchars.s, wildchars.len, lower.s[i - 1]) < wildchars.len) { r = cdb_seek(&cdb,lower.s,i,&dlen); if (r == -1) die_cdb(); if (r == 1) { /* OK */ if (substdio_putflush(subfdout, "K", 1) == -1) die_write(); cdb_free(&cdb); close(fd); return (1); } } --i; flagwild = 1; } while (i); close(fd); } return (0); }
int main() { unsigned int pos; char header[12]; char qtype[2]; char qclass[2]; const char *x; droproot(FATAL); dns_random_init(seed); axfr = env_get("AXFR"); x = env_get("TCPREMOTEIP"); if (x && ip6_scan(x,ip)) ; else byte_zero(ip,16); x = env_get("TCPREMOTEPORT"); if (!x) x = "0"; scan_ulong(x,&port); for (;;) { netread(tcpheader,2); uint16_unpack_big(tcpheader,&len); if (len > 512) strerr_die2x(111,FATAL,"excessively large request"); netread(buf,len); pos = dns_packet_copy(buf,len,0,header,12); if (!pos) die_truncated(); if (header[2] & 254) strerr_die2x(111,FATAL,"bogus query"); if (header[4] || (header[5] != 1)) strerr_die2x(111,FATAL,"bogus query"); pos = dns_packet_getname(buf,len,pos,&zone); if (!pos) die_truncated(); zonelen = dns_domain_length(zone); pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) die_truncated(); pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) die_truncated(); if (byte_diff(qclass,2,DNS_C_IN) && byte_diff(qclass,2,DNS_C_ANY)) strerr_die2x(111,FATAL,"bogus query: bad class"); pos = check_edns0(header, buf, len, pos); if (!pos) die_truncated(); qlog(ip,port,header,zone,qtype," "); if (byte_equal(qtype,2,DNS_T_AXFR)) { case_lowerb(zone,zonelen); fdcdb = open_read("data.cdb"); if (fdcdb == -1) die_cdbread(); doaxfr(header); close(fdcdb); } else { if (!response_query(zone,qtype,qclass)) nomem(); response[2] |= 4; case_lowerb(zone,zonelen); response_id(header); response[3] &= ~128; if (!(header[2] & 1)) response[2] &= ~1; if (!respond(zone,qtype,ip)) die_outside(); print(response,response_len); } } }
int std_subscribe(const char *dir, const char *subdir, const char *userhost, int flagadd, const char *comment, const char *event, int forcehash) /* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database */ /* dbname. Comment is e.g. the subscriber from line or name. It is added to */ /* the log. Event is the action type, e.g. "probe", "manual", etc. The */ /* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0 */ /* on failure. If flagmysql is set and the file "sql" is found in the */ /* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */ /* >=0 it is used in place of the calculated hash. This makes it possible to */ /* add addresses with a hash that does not exist. forcehash has to be 0..99. */ /* for unsubscribes, the address is only removed if forcehash matches the */ /* actual hash. This way, ezmlm-manage can be prevented from touching certain*/ /* addresses that can only be removed by ezmlm-unsub. Usually, this would be */ /* used for sublist addresses (to avoid removal) and sublist aliases (to */ /* prevent users from subscribing them (although the cookie mechanism would */ /* prevent the resulting duplicate message from being distributed. */ { int fdlock; unsigned int j; unsigned char ch,lcch; int match; int flagwasthere; if (userhost[str_chr(userhost,'\n')]) strerr_die2x(100,FATAL,ERR_ADDR_NL); if (!stralloc_copys(&addr,"T")) die_nomem(); if (!stralloc_cats(&addr,userhost)) die_nomem(); if (addr.len > 401) strerr_die2x(100,FATAL,ERR_ADDR_LONG); j = byte_rchr(addr.s,addr.len,'@'); if (j == addr.len) strerr_die2x(100,FATAL,ERR_ADDR_AT); case_lowerb(addr.s + j + 1,addr.len - j - 1); if (!stralloc_copy(&lcaddr,&addr)) die_nomem(); case_lowerb(lcaddr.s + 1,j - 1); /* make all-lc version of address */ if (forcehash >= 0 && forcehash <= 52) { ch = lcch = 64 + (unsigned char) forcehash; } else { ch = 64 + subhashsa(&addr); lcch = 64 + subhashsa(&lcaddr); } if (!stralloc_0(&addr)) die_nomem(); if (!stralloc_0(&lcaddr)) die_nomem(); std_makepath(&fn,dir,subdir,"/subscribers/",lcch); std_makepath(&fnlock,dir,subdir,"/lock",0); if (!stralloc_copyb(&fnnew,fn.s,fn.len-1)) die_nomem(); /* code later depends on fnnew = fn + 'n' */ if (!stralloc_cats(&fnnew,"n")) die_nomem(); if (!stralloc_0(&fnnew)) die_nomem(); fdlock = lockfile(fnlock.s); /* do lower case hashed version first */ fdnew = open_trunc(fnnew.s); if (fdnew == -1) die_write(); substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); flagwasthere = 0; fd = open_read(fn.s); if (fd == -1) { if (errno != error_noent) { close(fdnew); die_read(); } } else { substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); for (;;) { if (getln(&ss,&line,&match,'\0') == -1) { close(fd); close(fdnew); die_read(); } if (!match) break; if (line.len == addr.len) if (!case_diffb(line.s,line.len,addr.s)) { flagwasthere = 1; if (!flagadd) continue; } if (substdio_bput(&ssnew,line.s,line.len) == -1) { close(fd); close(fdnew); die_write(); } } close(fd); } if (flagadd && !flagwasthere) if (substdio_bput(&ssnew,addr.s,addr.len) == -1) { close(fdnew); die_write(); } if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(); } if (fsync(fdnew) == -1) { close(fdnew); die_write(); } close(fdnew); if (rename(fnnew.s,fn.s) == -1) strerr_die6sys(111,FATAL,ERR_MOVE,fnnew.s," to ",fn.s,": "); if ((ch == lcch) || flagwasthere) { close(fdlock); if (flagadd ^ flagwasthere) { if (!stralloc_0(&addr)) die_nomem(); logaddr(dir,subdir,event,addr.s+1,comment); return 1; } return 0; } /* If unsub and not found and hashed differ, OR */ /* sub and not found (so added with new hash) */ /* do the 'case-dependent' hash */ fn.s[fn.len - 2] = ch; fnnew.s[fnnew.len - 3] = ch; fdnew = open_trunc(fnnew.s); if (fdnew == -1) die_write(); substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); fd = open_read(fn.s); if (fd == -1) { if (errno != error_noent) { close(fdnew); die_read(); } } else { substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); for (;;) { if (getln(&ss,&line,&match,'\0') == -1) { close(fd); close(fdnew); die_read(); } if (!match) break; if (line.len == addr.len) if (!case_diffb(line.s,line.len,addr.s)) { flagwasthere = 1; continue; /* always want to remove from case-sensitive hash */ } if (substdio_bput(&ssnew,line.s,line.len) == -1) { close(fd); close(fdnew); die_write(); } } close(fd); } if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(); } if (fsync(fdnew) == -1) { close(fdnew); die_write(); } close(fdnew); if (rename(fnnew.s,fn.s) == -1) strerr_die6sys(111,FATAL,ERR_MOVE,fnnew.s," to ",fn.s,": "); close(fdlock); if (flagadd ^ flagwasthere) { if (!stralloc_0(&addr)) die_nomem(); logaddr(dir,subdir,event,addr.s+1,comment); return 1; } return 0; }
static void do_edit(const char *action) { unsigned int i; unsigned int len; char ch; /* only remote admins and only if -e is specified may edit */ if (!flagedit || remote.s == 0) strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE)); if (!ismod) strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED)); len = str_len(ACTION_EDIT); if (!case_starts(action,ACTION_EDIT)) len = str_len(ALT_EDIT); if (action[len]) { /* -edit.file, not just -edit */ if (action[len] != '.') strerr_die2x(100,FATAL,MSG(ERR_BAD_REQUEST)); showsend2("edit ",action+len+1); stralloc_copys(&fnedit,"text/"); stralloc_cats(&fnedit,action+len+1); stralloc_0(&fnedit); case_lowerb(fnedit.s,fnedit.len); i = 5; /* after the "text/" */ while ((ch = fnedit.s[i++])) { if (((ch > 'z') || (ch < 'a')) && (ch != '_')) strerr_die2x(100,FATAL,MSG(ERR_BAD_NAME)); if (ch == '_') fnedit.s[i-1] = '-'; } switch(slurp(fnedit.s,&text,1024)) { /* entire file! */ case -1: strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnedit.s)); case 0: strerr_die5x(100,FATAL,dir,"/",fnedit.s,MSG(ERR_NOEXIST)); } stralloc_copy(&line,&text); subst_nuls(&line); stralloc_cat(&line,&fnedit); /* including '\0' */ strnum[fmt_ulong(strnum,(unsigned long) when)] = 0; cookie(hash,key.s,key.len,strnum,line.s,"-e"); stralloc_copy(&confirm,&outlocal); stralloc_append(&confirm,'-'); stralloc_catb(&confirm,ACTION_ED,LENGTH_ED); stralloc_cats(&confirm,strnum); stralloc_append(&confirm,'.'); /* action part has been checked for bad chars */ stralloc_cats(&confirm,action + len + 1); stralloc_append(&confirm,'.'); stralloc_catb(&confirm,hash,COOKIE); stralloc_append(&confirm,'@'); stralloc_cat(&confirm,&outhost); stralloc_0(&confirm); set_cpconfirm(confirm.s,outlocal.len); set_cpaction(ACTION_ED); set_cphash(hash); set_cpwhen(when); qmail_puts(&qq,"Reply-To: "); quote2("ed,confirm.s); qmail_put(&qq,quoted.s,quoted.len); qmail_puts(&qq,"\n"); hdr_subject(MSG1(SUB_EDIT_REQUEST,action+len+1)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy(&qq,"text/edit-do",flagcd); (void) code_qputs(MSG(TXT_EDIT_START)); (void) code_qput(text.s,text.len); (void) code_qputs(MSG(TXT_EDIT_END)); } else { /* -edit only, so output list of editable files */ hdr_subject(MSG(SUB_EDIT_LIST)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/edit-list"); } qmail_puts(&qq,"\n\n"); copybottom(0); qmail_to(&qq,mod.s); }
const char *issub(const char *dir, const char *subdir, const char *userhost) /* Returns (char *) to match if userhost is in the subscriber database */ /* dir, 0 otherwise. dir is a base directory for a list and may NOT */ /* be NULL */ /* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/ { MYSQL_RES *result; MYSQL_ROW row; const char *ret; const char *table; unsigned long *lengths; unsigned int j; if ((ret = opensub(dir,subdir,&table))) { if (*ret) strerr_die2x(111,FATAL,ret); return std_issub(dir,subdir,userhost); } else { /* SQL version */ /* SELECT address FROM list WHERE address = 'userhost' AND hash */ /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */ /* even easier to defeat. Just faking sender to the list name would*/ /* work. Since sender checks for posts are bogus anyway, I don't */ /* know if it's worth the cost of the "WHERE ...". */ if (!stralloc_copys(&addr,userhost)) die_nomem(); j = byte_rchr(addr.s,addr.len,'@'); if (j == addr.len) return 0; case_lowerb(addr.s + j + 1,addr.len - j - 1); if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(); if (!stralloc_cats(&line,table)) die_nomem(); if (!stralloc_cats(&line," WHERE address = '")) die_nomem(); if (!stralloc_ready("ed,2 * addr.len + 1)) die_nomem(); if (!stralloc_catb(&line,quoted.s, mysql_escape_string(quoted.s,userhost,addr.len))) die_nomem(); if (!stralloc_cats(&line,"'")) die_nomem(); if (mysql_real_query(mysql,line.s,line.len)) /* query */ strerr_die2x(111,FATAL,mysql_error(mysql)); if (!(result = mysql_use_result(mysql))) strerr_die2x(111,FATAL,mysql_error(mysql)); row = mysql_fetch_row(result); ret = (char *) 0; if (!row) { /* we need to return the actual address as other */ /* dbs may accept user-*@host, but we still want */ /* to make sure to send to e.g the correct moderator*/ /* address. */ if (!mysql_eof(result)) strerr_die2x(111,FATAL,mysql_error(mysql)); } else { if (!(lengths = mysql_fetch_lengths(result))) strerr_die2x(111,FATAL,mysql_error(mysql)); if (!stralloc_copyb(&line,row[0],lengths[0])) die_nomem(); if (!stralloc_0(&line)) die_nomem(); ret = line.s; while ((row = mysql_fetch_row(result))); /* maybe not necessary */ mysql_free_result(result); } return ret; } }
/* Add (flagadd=1) or remove (flagadd=0) userhost from the subscriber * database table. Comment is e.g. the subscriber from line or name. It * is added to the log. Event is the action type, e.g. "probe", * "manual", etc. The direction (sub/unsub) is inferred from * flagadd. Returns 1 on success, 0 on failure. If forcehash is >=0 it * is used in place of the calculated hash. This makes it possible to * add addresses with a hash that does not exist. forcehash has to be * 0..99. For unsubscribes, the address is only removed if forcehash * matches the actual hash. This way, ezmlm-manage can be prevented from * touching certain addresses that can only be removed by * ezmlm-unsub. Usually, this would be used for sublist addresses (to * avoid removal) and sublist aliases (to prevent users from subscribing * them (although the cookie mechanism would prevent the resulting * duplicate message from being distributed. */ int sub_sql_subscribe(struct subdbinfo *info, const char *table, const char *userhost, int flagadd, const char *comment, const char *event, int forcehash) { void *result; char *cpat; char szhash[3] = "00"; unsigned int j; unsigned char ch; int nparams; make_name(info,table?"_":0,table,0); /* lowercase and check address */ stralloc_copys(&addr,userhost); if (addr.len > 255) /* this is 401 in std ezmlm. 255 */ /* should be plenty! */ strerr_die2x(100,FATAL,MSG(ERR_ADDR_LONG)); j = byte_rchr(addr.s,addr.len,'@'); if (j == addr.len) strerr_die2x(100,FATAL,MSG(ERR_ADDR_AT)); cpat = addr.s + j; case_lowerb(cpat + 1,addr.len - j - 1); if (forcehash < 0) { stralloc_copy(&lcaddr,&addr); case_lowerb(lcaddr.s,j); /* make all-lc version of address */ ch = subhashsa(&lcaddr); } else ch = (forcehash % 100); szhash[0] = '0' + ch / 10; /* hash for sublist split */ szhash[1] = '0' + (ch % 10); if (flagadd) { /* FIXME: LOCK TABLES name WRITE */ stralloc_copys(&query,"SELECT address FROM "); stralloc_cat(&query,&name); stralloc_cats(&query," WHERE "); stralloc_cats(&query,sql_subscribe_select_where_defn); stralloc_copy(¶ms[0],&addr); result = sql_select(info,&query,1,params); if (sql_fetch_row(info,result,1,params)) { sql_free_result(info,result); /* FIXME: UNLOCK TABLES */ return 0; /* already subscribed */ } else { /* not there */ sql_free_result(info,result); stralloc_copys(&query,"INSERT INTO "); stralloc_cat(&query,&name); stralloc_cats(&query," (address,hash) VALUES "); stralloc_cats(&query,sql_subscribe_list_values_defn); stralloc_copy(¶ms[0],&addr); stralloc_copys(¶ms[1],szhash); sql_exec(info,&query,2,params); /* FIXME: UNLOCK TABLES */ } } else { /* unsub */ stralloc_copys(&query,"DELETE FROM "); stralloc_cat(&query,&name); stralloc_cats(&query," WHERE "); stralloc_copy(¶ms[0],&addr); if (forcehash >= 0) { stralloc_cats(&query,sql_subscribe_delete2_where_defn); stralloc_copys(¶ms[1],szhash); nparams = 2; } else { stralloc_cats(&query,sql_subscribe_delete1_where_defn); nparams = 1; } if (sql_exec(info,&query,1,params) == 0) return 0; /* address wasn't there*/ } /* log to subscriber log */ /* INSERT INTO t_slog (address,edir,etype,fromline) */ /* VALUES('address',{'+'|'-'},'etype','[comment]') */ stralloc_copys(&query,"INSERT INTO "); stralloc_cat(&query,&name); stralloc_cats(&query,"_slog (address,edir,etype,fromline) VALUES "); stralloc_cats(&query,sql_subscribe_slog_values_defn); stralloc_copy(¶ms[0],&addr); stralloc_copys(¶ms[1],flagadd?"+":"-"); /* edir */ stralloc_copyb(¶ms[2],event+1,!!*(event+1)); /* etype */ stralloc_copys(¶ms[3],comment && *comment ? comment : ""); /* from */ sql_exec(info,&query,4,params); /* log (ignore errors) */ stralloc_0(&addr); logaddr(table,event,addr.s,comment); /* also log to old log */ return 1; /* desired effect */ }
main() { struct address t; int i; int j; int k; char ch; umask(022); if (!address_alloc_readyplus(&x,0)) nomem(); fd = open_read("data"); if (fd == -1) strerr_die2sys(111,FATAL,"unable to open data: "); buffer_init(&b,read,fd,bspace,sizeof bspace); fdcdb = open_trunc("data.tmp"); if (fdcdb == -1) die_datatmp(); if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp(); while (match) { ++linenum; if (getln(&b,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,"unable to read line: "); while (line.len) { ch = line.s[line.len - 1]; if ((ch != ' ') && (ch != '\t') && (ch != '\n')) break; --line.len; } if (!line.len) continue; j = 1; for (i = 0; i < NUMFIELDS; ++i) { if (j >= line.len) { if (!stralloc_copys(&f[i],"")) nomem(); } else { k = byte_chr(line.s + j,line.len - j,':'); if (!stralloc_copyb(&f[i],line.s + j,k)) nomem(); j += k + 1; } } switch(line.s[0]) { default: syntaxerror(": unrecognized leading character"); case '#': break; case '-': break; case '+': byte_zero(&t,sizeof t); if (!dns_domain_fromdot(&t.name,f[0].s,f[0].len)) nomem(); t.namelen = dns_domain_length(t.name); case_lowerb(t.name,t.namelen); if (!stralloc_0(&f[1])) nomem(); if (!ip4_scan(f[1].s,t.ip)) syntaxerror(": malformed IP address"); if (!stralloc_0(&f[2])) nomem(); if (!stralloc_0(&f[2])) nomem(); byte_copy(t.location,2,f[2].s); if (!address_alloc_append(&x,&t)) nomem(); break; case '%': if (!stralloc_0(&f[0])) nomem(); if (!stralloc_0(&f[0])) nomem(); if (!stralloc_copyb(&result,f[0].s,2)) nomem(); if (!stralloc_0(&f[1])) nomem(); if (!stralloc_copys(&key,"%")) nomem(); ipprefix_cat(&key,f[1].s); if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1) die_datatmp(); break; } } close(fd); address_sort(x.s,x.len); i = 0; while (i < x.len) { for (j = i + 1; j < x.len; ++j) if (address_diff(x.s + i,x.s + j)) break; if (!stralloc_copys(&key,"+")) nomem(); if (!stralloc_catb(&key,x.s[i].location,2)) nomem(); if (!stralloc_catb(&key,x.s[i].name,x.s[i].namelen)) nomem(); if (!stralloc_copys(&result,"")) nomem(); while (i < j) if (!stralloc_catb(&result,x.s[i++].ip,4)) nomem(); if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1) die_datatmp(); } if (cdb_make_finish(&cdb) == -1) die_datatmp(); if (fsync(fdcdb) == -1) die_datatmp(); if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */ if (rename("data.tmp","data.cdb") == -1) strerr_die2sys(111,FATAL,"unable to move data.tmp to data.cdb: "); _exit(0); }
void main() { int i; int numcolons; umask(033); if (chdir(auto_qmail) == -1) die_chdir(); fd = open_read("users/assign"); if (fd == -1) die_opena(); substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); fdtemp = open_trunc("users/cdb.tmp"); if (fdtemp == -1) die_opent(); if (cdbmss_start(&cdbmss,fdtemp) == -1) die_writet(); if (!stralloc_copys(&wildchars,"")) die_nomem(); for (;;) { if (getln(&ssin,&line,&match,'\n') != 0) die_reada(); if (line.len && (line.s[0] == '.')) break; if (!match) die_format(); if (byte_chr(line.s,line.len,'\0') < line.len) die_format(); i = byte_chr(line.s,line.len,':'); if (i == line.len) die_format(); if (i == 0) die_format(); if (!stralloc_copys(&key,"!")) die_nomem(); if (line.s[0] == '+') { if (!stralloc_catb(&key,line.s + 1,i - 1)) die_nomem(); case_lowerb(key.s,key.len); if (i >= 2) if (byte_chr(wildchars.s,wildchars.len,line.s[i - 1]) == wildchars.len) if (!stralloc_append(&wildchars,line.s + i - 1)) die_nomem(); } else { if (!stralloc_catb(&key,line.s + 1,i - 1)) die_nomem(); if (!stralloc_0(&key)) die_nomem(); case_lowerb(key.s,key.len); } if (!stralloc_copyb(&data,line.s + i + 1,line.len - i - 1)) die_nomem(); numcolons = 0; for (i = 0;i < data.len;++i) if (data.s[i] == ':') { data.s[i] = 0; if (++numcolons == 6) break; } if (numcolons < 6) die_format(); data.len = i; if (cdbmss_add(&cdbmss,key.s,key.len,data.s,data.len) == -1) die_writet(); } if (cdbmss_add(&cdbmss,"",0,wildchars.s,wildchars.len) == -1) die_writet(); if (cdbmss_finish(&cdbmss) == -1) die_writet(); if (fsync(fdtemp) == -1) die_writet(); if (close(fdtemp) == -1) die_writet(); /* NFS stupidity */ if (rename("users/cdb.tmp","users/cdb") == -1) die_rename(); _exit(0); }
/* Add (flagadd=1) or remove (flagadd=0) userhost from the subscriber * database table. Comment is e.g. the subscriber from line or name. It * is added to the log. Event is the action type, e.g. "probe", * "manual", etc. The direction (sub/unsub) is inferred from * flagadd. Returns 1 on success, 0 on failure. If forcehash is >=0 it * is used in place of the calculated hash. This makes it possible to * add addresses with a hash that does not exist. forcehash has to be * 0..99. For unsubscribes, the address is only removed if forcehash * matches the actual hash. This way, ezmlm-manage can be prevented from * touching certain addresses that can only be removed by * ezmlm-unsub. Usually, this would be used for sublist addresses (to * avoid removal) and sublist aliases (to prevent users from subscribing * them (although the cookie mechanism would prevent the resulting * duplicate message from being distributed. */ static int _subscribe(struct subdbinfo *info, const char *table, const char *userhost, int flagadd, const char *comment, const char *event, int forcehash) { sqlite3_stmt *stmt; char *cpat; char szhash[3] = "00"; int res; unsigned int j; unsigned char ch; domain.len = 0; /* clear domain */ /* lowercase and check address */ if (!stralloc_copys(&addr,userhost)) die_nomem(); if (addr.len > 255) /* this is 401 in std ezmlm. 255 */ /* should be plenty! */ strerr_die2x(100,FATAL,MSG(ERR_ADDR_LONG)); j = byte_rchr(addr.s,addr.len,'@'); if (j == addr.len) strerr_die2x(100,FATAL,MSG(ERR_ADDR_AT)); cpat = addr.s + j; case_lowerb(cpat + 1,addr.len - j - 1); if (!stralloc_copy("ed, &addr)) die_nomem(); /* stored unescaped, so it should be ok if quoted.len is >255, as */ /* long as addr.len is not */ if (forcehash < 0) { if (!stralloc_copy(&lcaddr,&addr)) die_nomem(); case_lowerb(lcaddr.s,j); /* make all-lc version of address */ ch = subhashsa(&lcaddr); } else ch = (forcehash % 100); szhash[0] = '0' + ch / 10; /* hash for sublist split */ szhash[1] = '0' + (ch % 10); if (flagadd) { if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(); if (!stralloc_cat_table(&line,info,table)) die_nomem(); if (!stralloc_cats(&line," WHERE address LIKE '")) die_nomem(); if (!stralloc_cat(&line,"ed)) die_nomem(); /* addr */ if (!stralloc_cats(&line,"'")) die_nomem(); if (!stralloc_0(&line)) die_nomem(); if ((stmt = _sqlquery(info, &line)) == NULL) strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn)); res = sqlite3_step(stmt); sqlite3_finalize(stmt); if (res == SQLITE_ROW) return 0; /* there */ else if (res != SQLITE_DONE) { strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn)); } else { /* not there */ if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem(); if (!stralloc_cat_table(&line,info,table)) die_nomem(); if (!stralloc_cats(&line," (address,hash) VALUES ('")) die_nomem(); if (!stralloc_cat(&line,"ed)) die_nomem(); /* addr */ if (!stralloc_cats(&line,"',")) die_nomem(); if (!stralloc_cats(&line,szhash)) die_nomem(); /* hash */ if (!stralloc_cats(&line,")")) die_nomem(); if (!stralloc_0(&line)) die_nomem(); if ((stmt = _sqlquery(info, &line)) == NULL) strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn)); if (sqlite3_step(stmt) != SQLITE_DONE) strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn)); sqlite3_finalize(stmt); } } else { /* unsub */ if (!stralloc_copys(&line,"DELETE FROM ")) die_nomem(); if (!stralloc_cat_table(&line,info,table)) die_nomem(); if (!stralloc_cats(&line," WHERE address LIKE '")) die_nomem(); if (!stralloc_cat(&line,"ed)) die_nomem(); /* addr */ if (forcehash >= 0) { if (!stralloc_cats(&line,"' AND hash=")) die_nomem(); if (!stralloc_cats(&line,szhash)) die_nomem(); } else { if (!stralloc_cats(&line,"' AND hash BETWEEN 0 AND 52")) die_nomem(); } if (!stralloc_0(&line)) die_nomem(); if ((stmt = _sqlquery(info, &line)) == NULL) strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn)); if (sqlite3_step(stmt) != SQLITE_DONE) strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn)); sqlite3_finalize(stmt); if (sqlite3_changes((sqlite3*)info->conn) == 0) return 0; /* address wasn't there*/ } /* log to subscriber log */ /* INSERT INTO t_slog (address,edir,etype,fromline) */ /* VALUES('address',{'+'|'-'},'etype','[comment]') */ if (!stralloc_copys(&logline,"INSERT INTO ")) die_nomem(); if (!stralloc_cat_table(&logline,info,table)) die_nomem(); if (!stralloc_cats(&logline, "_slog (tai,address,edir,etype,fromline) VALUES (")) die_nomem(); if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,now()))) die_nomem(); if (!stralloc_cats(&logline,",'")) die_nomem(); if (!stralloc_cat(&logline,"ed)) die_nomem(); if (flagadd) { /* edir */ if (!stralloc_cats(&logline,"','+','")) die_nomem(); } else { if (!stralloc_cats(&logline,"','-','")) die_nomem(); } if (*(event + 1)) /* ezmlm-0.53 uses '' for ezmlm-manage's work */ if (!stralloc_catb(&logline,event+1,1)) die_nomem(); /* etype */ if (!stralloc_cats(&logline,"','")) die_nomem(); if (comment && *comment) { j = str_len(comment); if (!stralloc_copys("ed, comment)) die_nomem(); /* from */ if (!stralloc_cat(&logline,"ed)) die_nomem(); } if (!stralloc_cats(&logline,"')")) die_nomem(); if (!stralloc_0(&logline)) die_nomem(); if ((stmt = _sqlquery(info, &logline)) != NULL) { sqlite3_step(stmt); /* log (ignore errors) */ sqlite3_finalize(stmt); } if (!stralloc_0(&addr)) ; /* ignore errors */ logaddr(table,event,addr.s,comment); /* also log to old log */ return 1; /* desired effect */ }
int findname(void) /* returns 1 if a matching line was found, 0 otherwise. name will contain */ /* the correct list address in either case */ { char *cpat,*cp1,*cp2,*cplast; const char *cpname; unsigned long u; unsigned char hash,hash_hi,hash_lo; unsigned int pos,pos_name,pos_hi; int fd,match; /* make case insensitive hash */ flagfound = 0; /* default */ cpname = ""; /* default */ if (!stralloc_copy(&lctarget,&target)) die_nomem(); case_lowerb(lctarget.s,lctarget.len -1); hash = subhashs(lctarget.s); /* make domain pointer */ cpat = lctarget.s + str_chr(lctarget.s,'@'); if (!*cpat) strerr_die4x(100,FATAL,ERR_ADDR_AT,": ",target.s); cplast = cpat + str_len(cpat) - 1; if (*cplast == '.') --cplast; /* annonying special case */ cp1 = cpat + byte_rchr(cpat,cplast - cpat, '.'); if (cp1 != cplast) { /* got one '.' */ if (!stralloc_copyb(&domain,cp1 + 1, cplast - cp1)) die_nomem(); cp2 = cpat + byte_rchr(cpat, cp1 - cpat,'.'); if (cp2 == cp1) cp2 = cpat; ++cp2; if (!stralloc_append(&domain,".")) die_nomem(); if (!stralloc_catb(&domain,cp2, cp1 - cp2)) die_nomem(); } else /* no '.' */ if (!stralloc_copyb(&domain,cpat + 1,cplast - cpat)) die_nomem(); if (!stralloc_0(&domain)) die_nomem(); if ((fd = open_read(split)) == -1) strerr_die4sys(111,FATAL,ERR_OPEN,split,": "); substdio_fdbuf(&sssp,read,fd,spbuf,(int) sizeof(spbuf)); lineno = 0; for (;;) { /* dom:hash_lo:hash_hi:listaddress */ if (getln(&sssp,&line,&match,'\n') == -1) strerr_die4sys(111,FATAL,ERR_READ,split,": "); lineno++; if (!match) break; if (line.s[0] == '#') continue; /* comment */ line.s[line.len - 1] = '\0'; /* no need to allow \0 in lines */ if (!line.s[pos = str_chr(line.s,':')]) continue; /* usually blank line */ line.s[pos] = '\0'; if (pos == 0 || /* no domain */ (case_starts(domain.s,line.s))) { /* or matching domain */ if (!line.s[++pos]) die_syntax(); pos_hi = pos + str_chr(line.s + pos,':'); if (!line.s[pos_hi]) die_syntax(); pos_hi++; (void) scan_ulong(line.s + pos, &u); /* scan_uint() not in ezmlm */ hash_lo = (unsigned char) u; (void) scan_ulong(line.s + pos_hi, &u); hash_hi = (unsigned char) u; pos_name = pos_hi + str_chr(line.s + pos_hi,':'); if (pos_hi == pos_name) hash_hi = 52L; /* default hi = 52 */ if (line.s[pos_name]) pos_name++; if (hash > hash_hi || hash < hash_lo) continue; /* not us */ cpname = line.s + pos_name; while (*cpname && /* isolate name */ (*cpname == ' ' || *cpname == '\t')) cpname++; pos = line.len - 2; while (pos && (line.s[pos] == '\n' || line.s[pos] == ' ' || line.s[pos] == '\t')) line.s[pos--] = '\0'; break; } } close(fd); if (*cpname) { if (!stralloc_copys(&name,cpname)) die_nomem(); if (byte_chr(name.s,name.len,'@') == name.len) { /* local sublist */ if (!stralloc_append(&name,"@")) die_nomem(); if (!stralloc_cat(&name,&outhost)) die_nomem(); } if (!stralloc_0(&name)) die_nomem(); return 1; } else { /* match without name or no match =>this list */ if (!stralloc_copy(&name,&outlocal)) die_nomem(); if (!stralloc_append(&name,"@")) die_nomem(); if (!stralloc_cat(&name,&outhost)) die_nomem(); if (!stralloc_0(&name)) die_nomem(); return 0; } }
int main (int argc, char *argv[]) { int n = 0; time_t t = 0; struct sigaction sa; char qtype[2]; char qclass[2]; char header[12]; const char *x = NULL; unsigned int pos = 0; unsigned long long qnum = 0; sa.sa_handler = handle_term; sigaction (SIGINT, &sa, NULL); sigaction (SIGTERM, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction (SIGPIPE, &sa, NULL); prog = strdup ((x = strrchr (argv[0], '/')) != NULL ? x + 1 : argv[0]); n = check_option (argc, argv); argc -= n; argv += n; if (mode & DAEMON) /* redirect stderr to a log file */ redirect_to_log (logfile, STDERR_FILENO); time (&t); memset (seed, 0, sizeof (seed)); strftime (seed, sizeof (seed), "%b-%d %Y %T %Z", localtime (&t)); warnx ("version %s: starting %s\n", VERSION, seed); set_timezone (); if (debug_level) warnx ("TIMEZONE: %s", env_get ("TZ")); read_conf (cfgfile); if (!debug_level) if ((x = env_get ("DEBUG_LEVEL"))) debug_level = atol (x); warnx ("DEBUG_LEVEL set to `%d'", debug_level); dns_random_init (seed); axfr = env_get ("AXFR"); if (debug_level) warnx ("AXFR set to `%s'", axfr); x = env_get ("TCPREMOTEIP"); if (debug_level) warnx ("TCPREMOTEIP set to `%s'", x); if (x) ip4_scan (x, ip); else byte_zero (ip, 4); x = env_get ("TCPREMOTEPORT"); if (debug_level) warnx ("TCPREMOTEPORT set to `%s'", x); if (!x) x = "0"; scan_ulong (x, &port); droproot (); for (;;) { netread (tcpheader, 2); uint16_unpack_big (tcpheader, &len); if (len > 512) errx (-1, "excessively large request"); netread (buf, len); pos = dns_packet_copy (buf, len, 0, header, 12); if (!pos) errx (-1, "truncated request"); if (header[2] & 254) errx (-1, "bogus query"); if (header[4] || (header[5] != 1)) errx (-1, "bogus query"); pos = dns_packet_getname (buf, len, pos, &zone); if (!pos) errx (-1, "truncated request"); zonelen = dns_domain_length (zone); pos = dns_packet_copy (buf, len, pos, qtype, 2); if (!pos) errx (-1, "truncated request"); pos = dns_packet_copy (buf, len, pos, qclass, 2); if (!pos) errx (-1, "truncated request"); if (byte_diff(qclass, 2, DNS_C_IN) && byte_diff(qclass, 2, DNS_C_ANY)) errx (-1, "bogus query: bad class"); log_query (++qnum, ip, port, header, zone, qtype); if (byte_equal(qtype,2,DNS_T_AXFR)) { case_lowerb (zone, zonelen); fdcdb = open_read ("data.cdb"); if (fdcdb == -1) errx (-1, "could not read from file `data.cdb'"); doaxfr (header); close (fdcdb); } else { if (!response_query (zone, qtype, qclass)) err (-1, "could not allocate enough memory"); response[2] |= 4; case_lowerb (zone, zonelen); response_id (header); response[3] &= ~128; if (!(header[2] & 1)) response[2] &= ~1; if (!respond (zone, qtype, ip)) errx (-1, "could not find information in file `data.cdb'"); print (response, response_len); } } }