X-Git-Url: https://git.distorted.org.uk/~mdw/ezmlm/blobdiff_plain/5b62e993b0af39700031c2875d7f6654e6a02850..f8beb284087c279acfb30506f5bb32baa4949b44:/sub_mysql/issub.c diff --git a/sub_mysql/issub.c b/sub_mysql/issub.c new file mode 100644 index 0000000..a2b760c --- /dev/null +++ b/sub_mysql/issub.c @@ -0,0 +1,174 @@ +/*$Id: issub.c,v 1.16 1999/12/11 03:04:19 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "strerr.h" +#include "error.h" +#include "uint32.h" +#include "fmt.h" +#include "subscribe.h" +#include "errtxt.h" +#include + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static stralloc addr = {0}; +static stralloc lcaddr = {0}; +static stralloc line = {0}; +static stralloc quoted = {0}; +static stralloc fn = {0}; +static substdio ss; +static char ssbuf[512]; +static char szh[FMT_ULONG]; + +char *issub(dbname,userhost,tab,fatal) +/* Returns (char *) to match if userhost is in the subscriber database */ +/* dbname, 0 otherwise. dbname 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!*/ + +char *dbname; /* directory to basedir */ +char *userhost; +char *tab; /* override table name */ +char *fatal; + +{ + MYSQL_RES *result; + MYSQL_ROW row; + char *ret; + char *table; + unsigned long *lengths; + + int fd; + unsigned int j; + uint32 h,lch; + char ch,lcch; + int match; + + table = tab; + if ((ret = opensql(dbname,&table))) { + if (*ret) strerr_die2x(111,fatal,ret); + /* fallback to local db */ + + if (!stralloc_copys(&addr,"T")) die_nomem(fatal); + if (!stralloc_cats(&addr,userhost)) die_nomem(fatal); + + 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_copy(&lcaddr,&addr)) die_nomem(fatal); + case_lowerb(lcaddr.s + 1,j - 1); /* totally lc version of addr */ + + h = 5381; + lch = h; /* make hash for both for backwards comp */ + for (j = 0;j < addr.len;++j) { /* (lcaddr.len == addr.len) */ + h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; + lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j]; + } + ch = 64 + (h % 53); + lcch = 64 + (lch % 53); + + if (!stralloc_0(&addr)) die_nomem(fatal); + if (!stralloc_0(&lcaddr)) die_nomem(fatal); + if (!stralloc_copys(&fn,dbname)) die_nomem(fatal); + if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal); + if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal); + if (!stralloc_0(&fn)) die_nomem(fatal); + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); + } else { + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + if (!match) break; + if (line.len == lcaddr.len) + if (!case_diffb(line.s,line.len,lcaddr.s)) + { close(fd); return line.s+1; } + } + + close(fd); + } + /* here if file not found or (file found && addr not there) */ + + if (ch == lcch) return 0; + + /* try case sensitive hash for backwards compatibility */ + fn.s[fn.len - 2] = ch; + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); + return 0; + } + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + if (!match) break; + if (line.len == addr.len) + if (!case_diffb(line.s,line.len,addr.s)) + { close(fd); return line.s+1; } + } + + close(fd); + + return 0; + } 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(fatal); + 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(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line," WHERE address = '")) die_nomem(fatal); + if (!stralloc_ready("ed,2 * addr.len + 1)) die_nomem(fatal); + if (!stralloc_catb(&line,quoted.s, + mysql_escape_string(quoted.s,userhost,addr.len))) die_nomem(fatal); + if (!stralloc_cats(&line,"'")) + die_nomem(fatal); + if (mysql_real_query((MYSQL *) psql,line.s,line.len)) /* query */ + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + if (!(result = mysql_use_result((MYSQL *) psql))) + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + 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 *) psql)); + } else { + if (!(lengths = mysql_fetch_lengths(result))) + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + if (!stralloc_copyb(&line,row[0],lengths[0])) die_nomem(fatal); + if (!stralloc_0(&line)) die_nomem(fatal); + ret = line.s; + while ((row = mysql_fetch_row(result))); /* maybe not necessary */ + mysql_free_result(result); + } + return ret; + } +}