--- orig/Makefile Mon Jun 15 11:53:16 1998 +++ Makefile Sun May 14 15:57:30 2000 @@ -1,9 +1,58 @@ # Don't edit Makefile! Use conf-* for configuration. +MYSQL_LIBS=/usr/local/mysql/lib/mysql/libmysqlclient.a -lm +MYSQL_INCLUDE=-I/usr/local/mysql/include +LOGGING=-DO_NOT_LOG SHELL=/bin/sh default: it +init_mysql.o: compile init_mysql.c auto_qmail.h + ./compile init_mysql.c $(MYSQL_INCLUDE) + +connect_mysql.o: compile connect_mysql.c + ./compile connect_mysql.c $(MYSQL_INCLUDE) + +vdoms_mysql.o: compile vdoms_mysql.c mysql_queries.h + ./compile vdoms_mysql.c $(MYSQL_INCLUDE) $(LOGGING) + +rcpthosts_mysql.o: compile rcpthosts_mysql.c mysql_queries.h + ./compile rcpthosts_mysql.c $(MYSQL_INCLUDE) $(LOGGING) + +checkuser_mysql.o: compile checkuser_mysql.c + ./compile checkuser_mysql.c $(MYSQL_INCLUDE) + +getpw_mysql.o: compile getpw_mysql.c mysql_queries.h + ./compile getpw_mysql.c $(MYSQL_INCLUDE) + +dotqmail_mysql.o: compile dotqmail_mysql.c mysql_queries.h + ./compile dotqmail_mysql.c $(MYSQL_INCLUDE) + +do_query.o: compile do_query.c + ./compile do_query.c $(MYSQL_INCLUDE) + +make_query.o: compile make_query.c mysql_queries.h + ./compile make_query.c $(MYSQL_INCLUDE) + +splog.o: compile splog.c + ./compile splog.c $(LOGGING) + +addrexp.o: \ +compile addrexp.c + ./compile addrexp.c + +addrexp: \ +load addrexp.o init_mysql.o connect_mysql.o make_query.o do_query.o \ +checkuser_mysql.o getpw_mysql.o vdoms_mysql.o \ +qsutil.o splog.o auto_qmail.o fmt_ulong.o fmt_uint.o fmt_uint0.o \ +open_read.o stralloc.a str.a getln.a case.a substdio.a error.a alloc.a \ +constmap.o control.o scan_ulong.o mysql_queries.h + ./load addrexp constmap.o control.o scan_ulong.o init_mysql.o \ + connect_mysql.o qsutil.o make_query.o do_query.o checkuser_mysql.o \ + getpw_mysql.o vdoms_mysql.o splog.o auto_qmail.o fmt_ulong.o \ + fmt_uint.o fmt_uint0.o open_read.o getln.a substdio.a stralloc.a \ + str.a error.a alloc.a case.a $(MYSQL_LIBS) + addresses.0: \ addresses.5 nroff -man addresses.5 > addresses.0 @@ -805,7 +854,7 @@ qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \ qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \ dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \ -forward preline condredirect bouncesaying except maildirmake \ +forward preline condredirect bouncesaying except maildirmake addrexp \ maildir2mbox maildirwatch qail elq pinq idedit install-big install \ instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \ binm3 binm3+df @@ -1109,9 +1158,14 @@ qmail-getpw: \ load qmail-getpw.o case.a substdio.a error.a str.a fs.a auto_break.o \ -auto_usera.o - ./load qmail-getpw case.a substdio.a error.a str.a fs.a \ - auto_break.o auto_usera.o +qsutil.o auto_usera.o auto_qmail.o init_mysql.o connect_mysql.o getpw_mysql.o \ +make_query.o do_query.o splog.o scan_ulong.o open_read.o \ +getln.a stralloc.a alloc.a substdio.a + ./load qmail-getpw \ + qsutil.o auto_break.o auto_usera.o auto_qmail.o init_mysql.o connect_mysql.o \ + getpw_mysql.o make_query.o do_query.o splog.o scan_ulong.o open_read.o \ + case.a substdio.a error.a str.a fs.a \ + getln.a stralloc.a alloc.a substdio.a env.a str.a $(MYSQL_LIBS) qmail-getpw.0: \ qmail-getpw.8 @@ -1172,14 +1226,16 @@ qmail-local: \ load qmail-local.o qmail.o quote.o now.o gfrom.o myctime.o \ -slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a lock.a fd.a \ +qsutil.o splog.o slurpclose.o init_mysql.o connect_mysql.o do_query.o \ +dotqmail_mysql.o case.a getln.a getopt.a sig.a open.a seek.a lock.a fd.a \ wait.a env.a stralloc.a alloc.a strerr.a substdio.a error.a str.a \ fs.a datetime.a auto_qmail.o auto_patrn.o socket.lib ./load qmail-local qmail.o quote.o now.o gfrom.o myctime.o \ - slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a \ + qsutil.o slurpclose.o init_mysql.o connect_mysql.o do_query.o \ + dotqmail_mysql.o splog.o case.a getln.a getopt.a sig.a open.a seek.a \ lock.a fd.a wait.a env.a stralloc.a alloc.a strerr.a \ substdio.a error.a str.a fs.a datetime.a auto_qmail.o \ - auto_patrn.o `cat socket.lib` + auto_patrn.o `cat socket.lib` $(MYSQL_LIBS) qmail-local.0: \ qmail-local.8 @@ -1480,15 +1536,18 @@ qmail-send: \ load qmail-send.o qsutil.o control.o constmap.o newfield.o prioq.o \ -trigger.o fmtqfn.o quote.o now.o readsubdir.o qmail.o date822fmt.o \ +trigger.o fmtqfn.o quote.o now.o readsubdir.o init_mysql.o connect_mysql.o \ +checkuser_mysql.o getpw_mysql.o vdoms_mysql.o make_query.o do_query.o splog.o qmail.o date822fmt.o \ datetime.a case.a ndelay.a getln.a wait.a seek.a fd.a sig.a open.a \ lock.a stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ auto_split.o ./load qmail-send qsutil.o control.o constmap.o newfield.o \ prioq.o trigger.o fmtqfn.o quote.o now.o readsubdir.o \ - qmail.o date822fmt.o datetime.a case.a ndelay.a getln.a \ + init_mysql.o connect_mysql.o checkuser_mysql.o getpw_mysql.o vdoms_mysql.o \ + make_query.o do_query.o splog.o qmail.o date822fmt.o datetime.a case.a ndelay.a getln.a \ wait.a seek.a fd.a sig.a open.a lock.a stralloc.a alloc.a \ - substdio.a error.a str.a fs.a auto_qmail.o auto_split.o + substdio.a error.a str.a fs.a auto_qmail.o auto_split.o \ + $(MYSQL_LIBS) qmail-send.0: \ qmail-send.8 @@ -1509,7 +1568,7 @@ scan.h case.h auto_qmail.h trigger.h newfield.h stralloc.h quote.h \ qmail.h substdio.h qsutil.h prioq.h datetime.h gen_alloc.h constmap.h \ fmtqfn.h readsubdir.h direntry.h - ./compile qmail-send.c + ./compile qmail-send.c $(MYSQL_INCLUDE) qmail-showctl: \ load qmail-showctl.o auto_uids.o control.o open.a getln.a stralloc.a \ @@ -1534,15 +1593,17 @@ qmail-smtpd: \ load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \ -date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \ +date822fmt.o now.o qmail.o init_mysql.o connect_mysql.o rcpthosts_mysql.o \ +qsutil.o do_query.o splog.o cdb.a fd.a wait.a datetime.a getln.a \ open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \ fs.a auto_qmail.o socket.lib ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \ - received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \ + qsutil.o received.o date822fmt.o now.o qmail.o init_mysql.o connect_mysql.o \ + rcpthosts_mysql.o do_query.o splog.o cdb.a fd.a wait.a \ datetime.a getln.a open.a sig.a case.a env.a stralloc.a \ alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \ - socket.lib` + socket.lib` $(MYSQL_LIBS) qmail-smtpd.0: \ qmail-smtpd.8 @@ -1950,11 +2011,11 @@ stralloc.a: \ makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \ stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \ -stralloc_catb.o stralloc_arts.o +stralloc_catb.o stralloc_arts.o stralloc_free.o ./makelib stralloc.a stralloc_eady.o stralloc_pend.o \ stralloc_copy.o stralloc_opys.o stralloc_opyb.o \ stralloc_cat.o stralloc_cats.o stralloc_catb.o \ - stralloc_arts.o + stralloc_arts.o stralloc_free.o stralloc_arts.o: \ compile stralloc_arts.c byte.h str.h stralloc.h gen_alloc.h @@ -1975,6 +2036,10 @@ stralloc_copy.o: \ compile stralloc_copy.c byte.h stralloc.h gen_alloc.h ./compile stralloc_copy.c + +stralloc_free.o: \ +compile stralloc_free.c stralloc.h gen_alloc.h + ./compile stralloc_free.c stralloc_eady.o: \ compile stralloc_eady.c alloc.h stralloc.h gen_alloc.h \ --- orig/addrexp.c Sun May 14 15:53:24 2000 +++ addrexp.c Fri May 12 15:05:09 2000 @@ -0,0 +1,108 @@ +#include "constmap.h" +#include "control.h" +#include "str.h" +#include "stralloc.h" +#include "substdio.h" +#include "subfd.h" +#include "mysql_queries.h" + +extern int connect_mysql(); +extern void disconnect_mysql(); +extern char *vdoms_mysql(); +extern int checkuser_mysql(); + +extern char auto_qmail[]; + +stralloc envnoathost = { 0 }; +stralloc locals = { 0 }; +stralloc percenthack = { 0 }; +stralloc qmail_mysql_query = { 0 }; +struct constmap maplocals; +struct constmap mappercenthack; + +int main(int argc, char **argv) { + int at, i, j, local; + stralloc addr = { 0 }; + stralloc ret = { 0 }; + + if (argc == 1) { + substdio_putsflush(subfdout, "addrexp: expand a virtual address\n"); + substdio_putsflush(subfdout, "usage: addrexp virtual_username@virtual_host\n"); + substdio_putsflush(subfdout, "returns: final delivery address for virtual_username@virtual_host\n"); + substdio_putsflush(subfdout, "exit codes: 0 if the address is local\n"); + substdio_putsflush(subfdout, " 1 if the address is a virtual domain\n"); + substdio_putsflush(subfdout, " 2 if the address is remote\n"); + substdio_putsflush(subfdout, " 100 if there was an error reading controls\n"); + substdio_putsflush(subfdout, " 111 if there was a database error\n"); + _exit(1); + } + + if (chdir(auto_qmail) == -1) _exit(100); + if (control_init() == -1) _exit(100); + if (control_rldef(&envnoathost, "control/envnoathost", 1, "envnoathost") == -1) _exit(100); + if (control_readfile(&locals,"control/locals",1) != 1) _exit(100); + if (!constmap_init(&maplocals,locals.s,locals.len,0)) _exit(100); + switch(control_readfile(&percenthack,"control/percenthack",0)) { + case -1: return 0; + case 0: if (!constmap_init(&mappercenthack,"",0,0)) return 0; break; + case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) return 0; break; + } + if (! stralloc_ready(&addr, str_len(argv[1]) + 1)) _exit(100); + if (! stralloc_cats(&addr, argv[1])) _exit(100); + + /* some of this ripped from qmail-send */ + i = byte_rchr(addr.s, addr.len, '@'); + if (i == addr.len) { + if (! stralloc_readyplus(&addr, envnoathost.len + 1)) _exit(100); + if (! stralloc_append(&addr, "@")) _exit(100); + if (! stralloc_cat(&addr, &envnoathost)) _exit(100); + } + + while (constmap(&mappercenthack,addr.s + i + 1,addr.len - i - 1)) { + j = byte_rchr(addr.s,i,'%'); + if (j == i) break; + addr.len = i; + i = j; + addr.s[i] = '@'; + } + + at = byte_rchr(addr.s,addr.len,'@'); + + if (! connect_mysql()) _exit(111); + local = 2; + i = 0; + if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) { + local = 1; /* maybe one day expand to alias etc */ +/*printf("checkuser_mysql(%s, %d) = ", addr.s, at);*/ + i = checkuser_mysql(addr.s, at); +/*printf("%d\n", i);*/ + if (i == -1) _exit(111); + if (i) { + if (!stralloc_cat(&ret,&addr)) _exit(100); + if (!stralloc_0(&ret)) _exit(100); + local = 0; + } + else { + /* try virtual with the given host - then fall back to envnoathost */ +/*printf("local vdoms_mysql(%s, %i, &ret) = ", addr.s, addr.len);*/ + i = vdoms_mysql(addr.s, addr.len, &ret); +/*printf("%d\n", i);*/ + if (i == -1) _exit(111); + if (i) local = 0; + else { + addr.len = at + 1; + if (! stralloc_cat(&addr, &envnoathost)) _exit(100); + } + } + } + + if (! i) if (i = vdoms_mysql(addr.s, addr.len, &ret)) local = 1; +/*printf("%d\n", i);*/ + if (i == -1) _exit(111); + + if (i) substdio_puts(subfdout, ret.s); + else substdio_puts(subfdout, argv[1]); + substdio_putsflush(subfdout, "\n"); + disconnect_mysql(); + _exit(local); +} --- orig/checkuser_mysql.c Sun May 14 15:53:24 2000 +++ checkuser_mysql.c Sat May 13 20:36:25 2000 @@ -0,0 +1,38 @@ +#include +#include "stralloc.h" + +extern int do_query(stralloc *query); +extern MYSQL_RES *result; + +int checkuser_mysql(char *username, int i) { + MYSQL_ROW row; + int j; + stralloc qmail_mysql_query = { 0 }; + stralloc user = { 0 }; + + if (! stralloc_ready(&user, i)) return -1; + if (! stralloc_catb(&user, username, i)) { + stralloc_free(&user); + return -1; + } + user.s[i] = '\0'; + if (! make_query(&qmail_mysql_query, user.s)) { + stralloc_free(&user); + return -1; + } + + stralloc_free(&user); + row = do_query(&qmail_mysql_query); + + switch ((int) row) { + case -1: return -1; break; + case 0: + for (j = i - 1; j > 0; j--) { + if (*(username + j) == '-') return checkuser_mysql(username, j); + } + return 0; + break; + } + mysql_free_result(result); + return 1; +} --- orig/connect_mysql.c Sun May 14 15:53:24 2000 +++ connect_mysql.c Sun May 14 15:44:19 2000 @@ -0,0 +1,46 @@ +#include +#include "stralloc.h" + +#define TRIES 3 + +/* let's alloc our strallocs */ +extern stralloc DB_HOST; +extern stralloc DB_USER; +extern stralloc DB_PASS; +extern stralloc DB_NAME; +extern stralloc DB_SOCK; +extern stralloc DB_PORT; + +extern MYSQL dbh, *mysql; +extern init_mysql(); + +int connect_mysql() { + char *sock; + int i, port; + + if (mysql && ! mysql_ping(&dbh)) return 1; + if (init_mysql() == -1) return -1; + if (DB_PORT.a > 0) port = atoi(DB_PORT.s); + else port = 0; + if (DB_SOCK.a > 0) sock = DB_SOCK.s; + else sock = (char) 0; + for (i = 0; i < TRIES; i++) { + mysql = mysql_real_connect(&dbh, DB_HOST.s, DB_USER.s, DB_PASS.s, DB_NAME.s, + port, sock, 0); + if (mysql) { splog("connect_mysql", " -- CONNECTED -- "); break; } + splog("mysql-error", mysql_error(&dbh)); + sleep(3); + } + stralloc_free(&DB_HOST); + stralloc_free(&DB_USER); + stralloc_free(&DB_PASS); + stralloc_free(&DB_NAME); + stralloc_free(&DB_PORT); + stralloc_free(&DB_SOCK); + if (i < TRIES) return 1; + else return 0; +} + +void disconnect_mysql() { + mysql_close(&dbh); +} --- orig/do_query.c Sun May 14 15:53:24 2000 +++ do_query.c Fri May 12 15:35:42 2000 @@ -0,0 +1,32 @@ +#include +#include "stralloc.h" + +extern MYSQL dbh, *mysql; +extern MYSQL_RES *result; + +extern splog(); + +/* run a given query and return 1 row only */ +MYSQL_ROW do_query(stralloc *query) { + int num; + + if (! connect_mysql()) return -1; + splog("qmail-mysql", query->s); + if (mysql_real_query(mysql, query->s, query->len) < 0) { + stralloc_free(query); + splog("mysql-error", mysql_error(&dbh)); + return -1; + } + stralloc_free(query); + if (! (result = mysql_store_result(mysql))) return -1; + + num = mysql_num_rows(result); + + if (num != 1) { + mysql_free_result(result); + return 0; + } + + return mysql_fetch_row(result); +} + --- orig/dotqmail_mysql.c Sun May 14 15:53:24 2000 +++ dotqmail_mysql.c Fri May 12 11:24:08 2000 @@ -0,0 +1,123 @@ +#include +#include "stralloc.h" +#include "mysql_queries.h" + +extern int init_mysql(); +extern int connect_mysql(); +extern int disconnect_mysql(); + +extern MYSQL dbh, *mysql; +extern MYSQL_RES *result; + +/* simulate reading a .qmail file from ye olde database */ +int dotqmail_mysql(char *username, char *ext, stralloc *sa, int bufsize) { + int i, len, num; + MYSQL_ROW row; + stralloc query = { 0 }; + stralloc user = { 0 }; + stralloc real_ext = { 0 }; + + /* initialise database handle or signal trouble */ + if (! connect_mysql()) return -1; + + i = str_len(username); + if (! stralloc_ready(&user, 2 * i + 1)) return zoiks(-1); + mysql_escape_string(user.s, username, i); + + i = str_len(ext); + if (! stralloc_ready(&real_ext, 2 * i + 1)) return zoiks(-1); + mysql_escape_string(real_ext.s, ext, i); + + num = 0; + if (*ext) { + /* make the query or signal an out of memory exception */ + len = str_len(ALIAS) + real_ext.len + user.len - 3; + if (! stralloc_ready(&query, len)) return zoiks(-1); + if (! stralloc_cats(&query, ALIAS1)) return zoiks(-1); + if (! stralloc_cats(&query, user.s)) return zoiks(-1); + if (! stralloc_cats(&query, ALIAS2)) return zoiks(-1); + if (! stralloc_cats(&query, real_ext.s)) return zoiks(-1); + if (! stralloc_cats(&query, "'")) return zoiks(-1); + if (! stralloc_0(&query)) return zoiks(-1); + + splog("qmail-mysql", query.s); + + /* do the query or signal to use .qmail */ + if (mysql_real_query(mysql, query.s, query.len) < 0) { + splog("mysql-error", mysql_error(&dbh)); + disconnect_mysql(); + return 0; + } + result = mysql_store_result(mysql); + if (!result) return zoiks(-1); + + num = mysql_num_rows(result); + } + + /* no rows: let's try the default alias */ + if (num == 0) { + mysql_free_result(result); + query.len = 0; + len = str_len(ALIAS) + user.len - 3; + if (! stralloc_ready(&query, len)) return zoiks(-1); + if (! stralloc_cats(&query, ALIAS1)) return zoiks(-1); + if (! stralloc_cats(&query, user.s)) return zoiks(-1); + if (! stralloc_cats(&query, ALIAS2)) return zoiks(-1); + if (! stralloc_append(&query, "'")) return zoiks(-1); + if (! stralloc_0(&query)) return zoiks(-1); + + splog("qmail-mysql", query.s); + + /* hmm, a function would have been nice here */ + if (mysql_real_query(mysql, query.s, query.len) < 0) { + splog("mysql-error", mysql_error(&dbh)); + disconnect_mysql(); + return 0; + } + + result = mysql_store_result(mysql); + if (!result) return zoiks(0); + + num = mysql_num_rows(result); + } + + /* well it looks like there's really no match */ + if (num == 0) return zoiks(0); + + for (i = 0; i < num; i++) { + row = mysql_fetch_row(result); + /* we need space for &blabla@crap\n\0 */ + len = str_len(row[0]) + str_len(row[1]) + 4; + if (! stralloc_readyplus(sa, len)) return zoiks(-1); + /* if the result is too big for the buffer we skip it */ + if (len > bufsize) continue; + /* if the alias username is a | we use the alias host value as the target */ + if (*row[0] == '|') { + /* skip if the pipe would break */ + if (str_len(row[1]) == 0) continue; + if (! stralloc_cats(sa, "| ")) return zoiks(-1); + } + /* . or / means delivery to a mailbox or maildir */ + else if (*row[0] == '/' || *row[0] == '.') { + *(row[0] + 1) = '\0'; + if (str_len(row[1]) == 0) continue; + if (! stralloc_cats(sa, row[0])) return zoiks(-1); + } + else { + if (! stralloc_cats(sa, "&")) return zoiks(-1); + if (! stralloc_cats(sa, row[0])) return zoiks(-1); + if (strcmp(row[1], "") && ! stralloc_cats(sa, "@")) return zoiks(-1); + } + if (! stralloc_cats(sa, row[1])) return zoiks(-1); + if (! stralloc_cats(sa, "\n")) return zoiks(-1); + } + + return zoiks(num); +} + +/* free memory used by query, disconnect from database and return */ +int zoiks(int ret) { + mysql_free_result(result); + disconnect_mysql(); + return ret; +} --- orig/dotqmail_mysql.h Sun May 14 15:53:24 2000 +++ dotqmail_mysql.h Fri May 12 11:24:08 2000 @@ -0,0 +1 @@ +int dotqmail_mysql(char *username, char *ext, stralloc *sa, int bufsize); --- orig/getpw_mysql.c Sun May 14 15:53:24 2000 +++ getpw_mysql.c Fri May 12 16:04:12 2000 @@ -0,0 +1,38 @@ +#include +#include "mysql_queries.h" +#include "stralloc.h" + +stralloc tmpname = { 0 }; +stralloc tmphome = { 0 }; +stralloc tmpshell = { 0 }; + +extern MYSQL_ROW do_query(stralloc *query); +extern int make_query(stralloc *query, char *username); + +/* get a pw entry from the database */ +int getpw_mysql(char *username, int *uid, int *gid) { + MYSQL_ROW row; + int num, len, ret; + stralloc qmail_mysql_query = { 0 }; + + if (! make_query(&qmail_mysql_query, username)) return -1; + if (! (int) row) return -1; + row = do_query(&qmail_mysql_query); + if ((int) row < 1) return (int) row; + + if (! stralloc_ready(&tmpname, str_len(username))) return -1; + if (! stralloc_copys(&tmpname, username)) return -1; + if (! stralloc_0(&tmpname)) return -1; + if (! stralloc_ready(&tmphome, str_len(row[2]))) return -1; + if (! stralloc_copys(&tmphome, row[2])) return -1; + if (! stralloc_0(&tmphome)) return -1; + if (! stralloc_ready(&tmpshell, str_len(row[3]))) return -1; + if (! stralloc_copys(&tmpshell, row[3])) return -1; + if (! stralloc_0(&tmpshell)) return -1; + + /* OK so we're assuming the database really does return ints */ + *uid = atoi(row[0]); + *gid = atoi(row[1]); + + return 1; +} --- orig/init_mysql.c Sun May 14 15:53:24 2000 +++ init_mysql.c Sun May 14 15:42:01 2000 @@ -0,0 +1,113 @@ +#include +#include "auto_qmail.h" +#include "readwrite.h" +#include "str.h" +#include "stralloc.h" +#include "substdio.h" +#include "subfd.h" + +#define SQLSERVER "/control/sqlserver" + +/* let's alloc our strallocs */ +stralloc DB_HOST = { 0 }; +stralloc DB_USER = { 0 }; +stralloc DB_PASS = { 0 }; +stralloc DB_NAME = { 0 }; +stralloc DB_SOCK = { 0 }; +stralloc DB_PORT = { 0 }; + +static char inbuf[64]; +MYSQL dbh, *mysql; +MYSQL_RES *result; + +/* read the config file and decide which server the database is on, what */ +/* username and password we need to connect to it and which database to use */ +/* return -1 if a bad error occurred, 0 if everything was OK or 1 if not */ +int init_mysql() { + int i, error, file, match; + substdio ss; + stralloc filename = { 0 }; + stralloc buf = { 0 }; + + if (mysql) return 1; + mysql = mysql_init(&dbh); + if (! mysql) return -1; + + /* get the filename of the sqlserver control file */ + i = str_len(SQLSERVER) + str_len(auto_qmail) + 1; + if (! stralloc_ready(&filename, i)) return -1; + if (! stralloc_cats(&filename, auto_qmail)) return -1; + if (! stralloc_cats(&filename, SQLSERVER)) return -1; + if (! stralloc_0(&filename)) return -1; + + /* try to open the file - much code robbed from control.c*/ + file = open_read(filename.s); + if (file == -1) { + substdio_puts(subfderr, "warning: could not open sqlserver file "); + substdio_puts(subfderr, filename.s); + substdio_putsflush(subfderr, "\n"); + return 0; + } + substdio_fdbuf(&ss, read, file, inbuf, sizeof(inbuf)); + + i = 0; + while (getln(&ss, &buf, &match, '\n') != -1) { + if (! match && ! buf.len) break; + buf.len--; + if (! stralloc_0(&buf)) break; + /* we consider only lines starting with the letters s,l,p or d */ + switch (buf.s[0]) { + case 's': + if (buf.s[1] == 'e') error = getconfig(&buf, "server", &DB_HOST); + else error = getconfig(&buf, "socket", &DB_SOCK); + break; + case 'l': error = getconfig(&buf, "login", &DB_USER); break; + case 'p': + if (buf.s[1] == 'a') error = getconfig(&buf, "password", &DB_PASS); + else error = getconfig(&buf, "port", &DB_PORT); + break; + case 'd': error = getconfig(&buf, "db", &DB_NAME); break; + default: continue; + } + if (error == -1) { + i = -1; + continue; + } + else i += error; + if (! match) break; + } + close(file); + + if (i == -1) + substdio_putsflush(subfderr, "warning: there were errors reading sqlserver file\n"); + else if (i > 0) { + substdio_putsflush(subfderr, "warning: bogus lines in sqlserver file\n"); + i = 0; + } + return i; +} + +/* read lines in the config file and grok entries of the form "x=y" or "x y" */ +/* got is the line in the file, expected is the parmeter we're checking for */ +/* and store is a stralloc to put the result into if it was found */ +int getconfig(stralloc *got, char *expected, stralloc *store) { + char *value, *x; + + x = got->s + str_len(expected); + value = x + 1; + /* we got a meaningful value */ + if (! stralloc_starts(&got, expected) && (*x == ' ' || *x == '=') && str_len(value) > 0) { + if (! stralloc_ready(store, str_len(value))) return -1; + if (! stralloc_cats(store, value)) return -1; + if (! stralloc_0(store)) return -1; + return 0; + } + /* oh dear, the line we got didn't contain what we expected it to */ + substdio_puts(subfderr, "error reading sqlserver file: expected '"); + substdio_puts(subfderr, expected); + substdio_puts(subfderr, "' but got '"); + substdio_puts(subfderr, got); + substdio_putsflush(subfderr, "'\n"); + /* of course, we might have been expecting the wrong thing... */ + return 1; +} --- orig/make_query.c Sun May 14 15:53:24 2000 +++ make_query.c Sat May 13 20:35:48 2000 @@ -0,0 +1,20 @@ +#include "mysql_queries.h" +#include "stralloc.h" + +int make_query(stralloc *query, char *username) { + int i, len; + stralloc user = { 0 }; + + i = 2 * str_len(username) + 1; + if (! stralloc_ready(&user, i)) return 0; + mysql_escape_string(user.s, username, str_len(username)); + + len = str_len(QUERY) + user.len + 2; + if (! stralloc_ready(query, len)) { stralloc_free(&user); return 0; } + if (! stralloc_cats(query, QUERY)) { stralloc_free(&user); return 0; } + if (! stralloc_cats(query, user.s)) { stralloc_free(&user); return 0; } + stralloc_free(&user); + if (! stralloc_cats(query, "'")) return 0; + if (! stralloc_0(query)) return 0; + return 1; +} --- orig/mysql_queries.h Sun May 14 15:53:25 2000 +++ mysql_queries.h Fri May 12 11:24:08 2000 @@ -0,0 +1,34 @@ +/******************************************************************************/ +/* We define two queries that will be used to authenticate users from the */ +/* database. QUERY will be used to check for normal mailboxes and */ +/* VIRTUAL will query virtual domains */ +/* Furthermore we define the query that will allow us to expand aliases */ +/******************************************************************************/ + +/* virtual host query */ +#ifndef VIRTUAL +#define VIRTUAL1 "select username, ext from virtual where (virtual_username='' or virtual_username='" +#define VIRTUAL2 "') and virtual_host='" +#define VIRTUAL3 "' order by virtual_username desc limit 1" +#define VIRTUAL VIRTUAL1 VIRTUAL2 VIRTUAL3 +#endif + +/* standard query */ +#define QUERY "select uid, gid, home, '/bin/false' from mailbox where username='" + +/* if we couldn't find a user we process an alias */ +#ifndef ALIAS +#define ALIAS1 "select alias_username, alias_host from alias where username='" +#define ALIAS2 "' and alias='" +#define ALIAS ALIAS1 ALIAS2 +#endif + +/* is this domain in rcpthosts */ +#ifndef RCPTHOSTS +#define RCPTHOSTS "select count(*) from rcpthosts where host='" +#endif + +/* and can we deliver to it */ +#ifndef LOCALS +#define LOCALS "select count(*) from virtual where virtual_host='" +#endif --- orig/qmail-getpw.c Mon Jun 15 11:53:16 1998 +++ qmail-getpw.c Fri May 12 16:03:51 2000 @@ -13,18 +13,29 @@ #include "auto_usera.h" #include "auto_break.h" #include "qlx.h" +#include "stralloc.h" #define GETPW_USERLEN 32 +extern int getpw_mysql (char *username, int *UID, int *GID); +extern void disconnect_mysql(); +extern int connect_mysql(); + char *local; struct passwd *pw; char *dash; char *extension; +int connection; + +extern stralloc tmpname; +extern stralloc tmphome; +extern stralloc tmpshell; int userext() { char username[GETPW_USERLEN]; struct stat st; + int num, uid, gid; extension = local + str_len(local); for (;;) { @@ -34,8 +45,19 @@ username[extension - local] = 0; case_lowers(username); errno = 0; - pw = getpwnam(username); if (errno == error_txtbsy) _exit(QLX_SYS); + num = 0; + if (connection) num = getpw_mysql(username, &uid, &gid); + if (num == -1) _exit(QLX_SYS); + else if (num) { + pw = (struct passwd *) malloc(sizeof(struct passwd *)); + pw->pw_name = tmpname.s; + pw->pw_uid = uid; + pw->pw_gid = gid; + pw->pw_dir = tmphome.s; + pw->pw_shell = tmpshell.s; + } + if (! pw) pw = getpwnam(username); if (pw) if (pw->pw_uid) if (stat(pw->pw_dir,&st) == 0) { @@ -48,7 +70,13 @@ else if (error_temp(errno)) _exit(QLX_NFS); } - if (extension == local) return 0; + if (extension == local) { + /* we didn't find a system account */ + /* but the database is down */ + if (connection) return 0; + disconnect_mysql(); + _exit(QLX_SYS); + } --extension; } } @@ -62,11 +90,15 @@ local = argv[1]; if (!local) _exit(100); + connection = connect_mysql(); + if (!userext()) { extension = local; dash = "-"; pw = getpwnam(auto_usera); } + + if (connection) disconnect_mysql(); if (!pw) _exit(QLX_NOALIAS); --- orig/qmail-local.c Mon Jun 15 11:53:16 1998 +++ qmail-local.c Fri May 12 11:24:08 2000 @@ -28,6 +28,7 @@ #include "myctime.h" #include "gfrom.h" #include "auto_patrn.h" +#include "dotqmail_mysql.h" void usage() { strerr_die1x(100,"qmail-local: usage: qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty"); } @@ -458,6 +459,7 @@ datetime_sec starttime; int flagforwardonly; char *x; + int mysql_alias; umask(077); sig_pipeignore(); @@ -584,9 +586,14 @@ flagforwardonly = 0; qmesearch(&fd,&flagforwardonly); - if (fd == -1) - if (*dash) - strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)"); + mysql_alias = dotqmail_mysql(user, ext, &cmds, 256); + if (mysql_alias == -1) temp_nomem(); + if (mysql_alias == 0) { + if (fd == -1 && *dash) { + strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)"); + } + } + else close(fd); if (!stralloc_copys(&ueo,sender)) temp_nomem(); if (str_diff(sender,"")) @@ -611,8 +618,7 @@ if (!env_put2("NEWSENDER",ueo.s)) temp_nomem(); if (!stralloc_ready(&cmds,0)) temp_nomem(); - cmds.len = 0; - if (fd != -1) + if (mysql_alias == 0 && fd != -1) if (slurpclose(fd,&cmds,256) == -1) temp_nomem(); if (!cmds.len) --- orig/qmail-send.c Mon Jun 15 11:53:16 1998 +++ qmail-send.c Fri May 12 16:14:08 2000 @@ -1,3 +1,4 @@ +#include #include #include #include "readwrite.h" @@ -42,6 +43,12 @@ #define SLEEP_SYSFAIL 123 #define OSSIFIED 129600 /* 36 hours; _must_ exceed q-q's DEATH (24 hours) */ +extern int checkuser_mysql(char *username, int i); +extern int vdoms_mysql(char *host, int len, stralloc *store); + +extern MYSQL dbh, *mysql; +extern MYSQL_RES *result; + int lifetime = 604800; stralloc percenthack = {0}; @@ -119,7 +126,7 @@ int j; char *x; static stralloc addr = {0}; - int at; + int at, ret; if (!stralloc_copys(&rwline,"T")) return 0; if (!stralloc_copys(&addr,recip)) return 0; @@ -139,13 +146,29 @@ } at = byte_rchr(addr.s,addr.len,'@'); + i = 0; + ret = 2; if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) { - if (!stralloc_cat(&rwline,&addr)) return 0; - if (!stralloc_0(&rwline)) return 0; - return 1; + ret = 1; + i = checkuser_mysql(addr.s, at); + if (i == -1) return 0; + if (i) { + if (!stralloc_cat(&rwline,&addr)) return 0; + if (!stralloc_0(&rwline)) return 0; + return 1; + } + i = vdoms_mysql(addr.s, addr.len, &rwline); + if (i == -1) return 0; + if (i) return 1; + addr.len = at + 1; + if (!stralloc_cat(&addr, &envnoathost)) return 0; } + i = vdoms_mysql(addr.s, addr.len, &rwline); + if (i == -1) return 0; + if (i == 1) return 1; + for (i = 0;i <= addr.len;++i) if (!i || (i == at + 1) || (i == addr.len) || ((i > at) && (addr.s[i] == '.'))) if (x = constmap(&mapvdoms,addr.s + i,addr.len - i)) { @@ -159,7 +182,7 @@ if (!stralloc_cat(&rwline,&addr)) return 0; if (!stralloc_0(&rwline)) return 0; - return 2; + return ret; } void senderadd(sa,sender,recip) --- orig/qmail-smtpd.c Mon Jun 15 11:53:16 1998 +++ qmail-smtpd.c Fri May 12 12:18:58 2000 @@ -24,9 +24,14 @@ #include "timeoutwrite.h" #include "commands.h" +extern int connect_mysql(); +extern void disconnect_mysql(); +extern int rcpthosts_mysql(char *host, int len); + #define MAXHOPS 100 unsigned int databytes = 0; int timeout = 1200; +stralloc qmail_mysql_query = { 0 }; int safewrite(fd,buf,len) int fd; char *buf; int len; { @@ -45,6 +50,7 @@ void die_read() { _exit(1); } void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); } void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); } +void die_mysql() { out("421 who killed the MySQL server? (#4.3.0)\r\n"); flush(); _exit(1); } void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); } void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); } void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); } @@ -73,6 +79,7 @@ } void smtp_quit() { + disconnect_mysql(); smtp_greet("221 "); out("\r\n"); flush(); _exit(0); } @@ -213,6 +220,8 @@ int r; r = rcpthosts(addr.s,str_len(addr.s)); if (r == -1) die_control(); + if (! r) r = rcpthosts_mysql(addr.s,str_len(addr.s)); + if (r == -1) die_control(); return r; } @@ -411,6 +420,7 @@ void main() { sig_pipeignore(); + if (! connect_mysql()) die_mysql(); if (chdir(auto_qmail) == -1) die_control(); setup(); if (ipme_init() != 1) die_ipme(); --- orig/rcpthosts_mysql.c Sun May 14 15:53:25 2000 +++ rcpthosts_mysql.c Sun May 14 15:46:17 2000 @@ -0,0 +1,62 @@ +#include +#include "control.h" +#include "mysql_queries.h" +#include "stralloc.h" + +extern int connect_mysql(); + +extern MYSQL dbh, *mysql; +extern MYSQL_RES *result; + +extern MYSQL_ROW do_query(stralloc *query); + +/* qmail-smtpd needs to know if it can accept delivery for this domain */ +int rcpthosts_mysql(char *addr, int len) { + char *host; + int i, num; + MYSQL_ROW row; + stralloc real_host = { 0 }; + stralloc qmail_mysql_query = { 0 }; + + /* maybe the client's so slow we lost the MySQL connection... */ + if (! connect_mysql()) return -1; + + num = len; + host = addr + len; + while (*host != '@') { + host--; + num--; + if (host == addr) break; + } + + /* no @ => envnoathost */ + if (num == 0) return 1; + + /* let's lose the @ we found and adjust len */ + host++; + + if (! stralloc_ready(&real_host, 2 * str_len(host) + 1)) return -1; + mysql_escape_string(real_host.s, host, str_len(host)); + +#define OOF {\ + stralloc_free(&real_host);\ + stralloc_free(&qmail_mysql_query);\ + return -1;\ +} + len = real_host.len + str_len(RCPTHOSTS) + 2; + if (! stralloc_ready(&qmail_mysql_query, len)) OOF + if (! stralloc_cats(&qmail_mysql_query, RCPTHOSTS)) OOF + if (! stralloc_cats(&qmail_mysql_query, real_host.s)) OOF + if (! stralloc_cats(&qmail_mysql_query, "'")) OOF + if (! stralloc_0(&qmail_mysql_query)) OOF + stralloc_free(&real_host); + + row = do_query(&qmail_mysql_query); + + if ((int) row == 0) return -1; + + num = atoi(row[0]); + mysql_free_result(result); + + return num; +} --- orig/splog.c Sun May 14 15:53:25 2000 +++ splog.c Fri May 12 11:24:08 2000 @@ -0,0 +1,83 @@ +/* additional modifications by William Tan */ +#ifndef O_NOT_LOG +#include +#include +#include +#include "error.h" +#include "qsutil.h" +#include "stralloc.h" +#include "substdio.h" +#include "subfd.h" +#include "exit.h" +#include "str.h" +#include "scan.h" +#include "fmt.h" + +/* declare a global dummy copy of the message to be logged */ +static stralloc real_message = { 0 }; + +char fixedbuf[800]; /* syslog truncates long lines (or crashes); GPACIC */ +int bufpos = 0; /* 0 <= bufpos < sizeof(buf) */ +int flagcont = 0; +int priority; /* defined if flagcont */ +char stamp[FMT_ULONG + FMT_ULONG + 3]; /* defined if flagcont */ + +void stamp_make() +{ + struct timeval tv; + char *s; + gettimeofday(&tv,(struct timezone *) 0); + s = stamp; + s += fmt_ulong(s,(unsigned long) tv.tv_sec); + *s++ = '.'; + s += fmt_uint0(s,(unsigned int) tv.tv_usec,6); + *s = 0; +} + +void splogflush() +{ + if (bufpos) { + fixedbuf[bufpos] = 0; + if (flagcont) + syslog(priority,"%s+%s",stamp,fixedbuf); /* logger folds invisibly; GPACIC */ + else { + stamp_make(); + priority = LOG_INFO; + if (str_start(fixedbuf,"warning:")) priority = LOG_WARNING; + if (str_start(fixedbuf,"alert:")) priority = LOG_ALERT; + syslog(priority,"%s %s",stamp,fixedbuf); + flagcont = 1; + } + } + bufpos = 0; +} + +void splog(char *splogger, char *message) +{ + int i; + int max = sizeof(fixedbuf) - 1; + + while (! stralloc_copys(&real_message, message)) nomem(); + if (! stralloc_0(&real_message)) nomem(); + + openlog(splogger, 0, LOG_MAIL); + for (i = 0; real_message.s[i] != '\0' && i < max - 1; i++) { + if (real_message.s[i] == '\n') { splogflush(); flagcont = 0; continue; } + if (bufpos == max) splogflush(); + if ((real_message.s[i] < 32) || (real_message.s[i] > 126)) + real_message.s[i] = '?'; /* logger truncates at 0; GPACIC */ + fixedbuf[bufpos++] = real_message.s[i]++; + } + if (bufpos < max) { + i++; + fixedbuf[bufpos++] = '\n'; + splogflush(); + } + real_message.len = 0; + closelog(); + return; +} +#else +void splog(char *splogger, char *message) { +} +#endif --- orig/stralloc_free.c Sun May 14 15:53:25 2000 +++ stralloc_free.c Fri May 12 11:49:45 2000 @@ -0,0 +1,6 @@ +#include "stralloc.h" + +void stralloc_free(stralloc *labrat) { + alloc_free(labrat->s); + labrat->len = 0; +} --- orig/stralloc.h Mon Jun 15 11:53:16 1998 +++ stralloc.h Fri May 12 12:08:10 2000 @@ -13,6 +13,7 @@ extern int stralloc_cats(); extern int stralloc_copyb(); extern int stralloc_catb(); +extern void stralloc_free(); extern int stralloc_append(); /* beware: this takes a pointer to 1 char */ extern int stralloc_starts(); --- orig/stralloc.3 Mon Jun 15 11:53:16 1998 +++ stralloc.3 Sun May 14 15:52:06 2000 @@ -23,6 +23,8 @@ int \fBstralloc_append\fP(&\fIsa\fR,\fIbuf\fR); .br int \fBstralloc_0\fP(&\fIsa\fR); +.br +int \fBstralloc_free\fP(&\fIsa\fR); int \fBstralloc_starts\fP(&\fIsa\fR,\fIbuf\fR); @@ -134,6 +136,15 @@ adds a single 0 character to .IR sa . + +.B stralloc_free +frees the memory allocated to +.IR sa +by calling +.IR alloc_free(sa->s) +and setting +.IR sa->len +to 0 .B stralloc_starts returns 1 if the 0-terminated string --- orig/vdoms_mysql.c Sun May 14 15:53:25 2000 +++ vdoms_mysql.c Fri May 12 16:03:08 2000 @@ -0,0 +1,87 @@ +#include +#include "control.h" +#include "mysql_queries.h" +#include "stralloc.h" + +extern int connect_mysql(); + +extern MYSQL dbh, *mysql; +extern MYSQL_RES *result; +extern stralloc envnoathost; + +extern MYSQL_ROW do_query(stralloc *query); + +/* map a virtual domain to a user-ext stralloc */ +int vdoms_mysql(char *addr, int len, stralloc *ret) { + char *host; + int at, num; + MYSQL_ROW row; + stralloc qmail_mysql_query = { 0 }; + stralloc real_addr = { 0 }; + stralloc real_host = { 0 }; + + /* stralloc we're passed is unterminated */ + addr[len] = '\0'; + splog("vdoms_mysql", addr); + num = len; + host = addr + len; + while (*host != '@') { + host--; + num--; + if (host == addr) break; + } + at = num; + + /* let's lose the @ we found */ + host++; + if (! stralloc_ready(&real_addr, 2 * str_len(addr) + 1)) return -1; + mysql_escape_string(real_addr.s, addr, at); + if (! stralloc_ready(&real_host, 2 * str_len(host) + 1)) { + stralloc_free(&real_addr); + return -1; + } + mysql_escape_string(real_host.s, host, str_len(host)); + +#define ACK {\ + stralloc_free(&real_addr);\ + stralloc_free(&real_host);\ + stralloc_free(&qmail_mysql_query);\ + return -1;\ +} + if (connect_mysql() < 1) ACK + + len += real_addr.len + real_host.len + str_len(VIRTUAL) + 2; + if (! stralloc_ready(&qmail_mysql_query, len)) ACK + if (! stralloc_cats(&qmail_mysql_query, VIRTUAL1)) ACK + if (! stralloc_cats(&qmail_mysql_query, real_addr.s)) ACK + if (! stralloc_cats(&qmail_mysql_query, VIRTUAL2)) ACK + if (! stralloc_cats(&qmail_mysql_query, real_host.s)) ACK + if (! stralloc_cats(&qmail_mysql_query, VIRTUAL3)) ACK + if (! stralloc_0(&qmail_mysql_query)) ACK + + row = do_query(&qmail_mysql_query); + + /* no row doesn't mean an error */ + if ((int) row < 1) return (int) row; + +#define YOW {\ + stralloc_free(&real_addr);\ + stralloc_free(&real_host);\ + mysql_free_result(result);\ + return -1;\ +} + num = str_len(row[0]) + str_len(row[1]) + 2; + if (! stralloc_cats(ret, row[0])) YOW /* username */ + if (str_len(row[1])) { + if (! stralloc_append(ret, "-")) YOW + if (*row[1] != '@') { if (! stralloc_cats(ret, row[1])) YOW } + else if (! stralloc_cats(ret, real_addr)) YOW /* ext */ + } + mysql_free_result(result); + stralloc_free(&real_addr); + stralloc_free(&real_host); + if (! stralloc_append(ret, "@")) return -1; + if (! stralloc_cat(ret, &envnoathost)) return -1; + if (! stralloc_0(ret)) return -1; + return 1; +}