Commit | Line | Data |
---|---|---|
f8beb284 MW |
1 | /*$Id: issub.c,v 1.16 1999/12/11 03:04:19 lindberg Exp $*/ |
2 | /*$Name: ezmlm-idx-040 $*/ | |
3 | #include "stralloc.h" | |
4 | #include "getln.h" | |
5 | #include "readwrite.h" | |
6 | #include "substdio.h" | |
7 | #include "open.h" | |
8 | #include "byte.h" | |
9 | #include "case.h" | |
10 | #include "strerr.h" | |
11 | #include "error.h" | |
12 | #include "uint32.h" | |
13 | #include "fmt.h" | |
14 | #include "subscribe.h" | |
15 | #include "errtxt.h" | |
16 | #include <mysql.h> | |
17 | ||
18 | static void die_nomem(fatal) | |
19 | char *fatal; | |
20 | { | |
21 | strerr_die2x(111,fatal,ERR_NOMEM); | |
22 | } | |
23 | ||
24 | static stralloc addr = {0}; | |
25 | static stralloc lcaddr = {0}; | |
26 | static stralloc line = {0}; | |
27 | static stralloc quoted = {0}; | |
28 | static stralloc fn = {0}; | |
29 | static substdio ss; | |
30 | static char ssbuf[512]; | |
31 | static char szh[FMT_ULONG]; | |
32 | ||
33 | char *issub(dbname,userhost,tab,fatal) | |
34 | /* Returns (char *) to match if userhost is in the subscriber database */ | |
35 | /* dbname, 0 otherwise. dbname is a base directory for a list and may NOT */ | |
36 | /* be NULL */ | |
37 | /* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/ | |
38 | ||
39 | char *dbname; /* directory to basedir */ | |
40 | char *userhost; | |
41 | char *tab; /* override table name */ | |
42 | char *fatal; | |
43 | ||
44 | { | |
45 | MYSQL_RES *result; | |
46 | MYSQL_ROW row; | |
47 | char *ret; | |
48 | char *table; | |
49 | unsigned long *lengths; | |
50 | ||
51 | int fd; | |
52 | unsigned int j; | |
53 | uint32 h,lch; | |
54 | char ch,lcch; | |
55 | int match; | |
56 | ||
57 | table = tab; | |
58 | if ((ret = opensql(dbname,&table))) { | |
59 | if (*ret) strerr_die2x(111,fatal,ret); | |
60 | /* fallback to local db */ | |
61 | ||
62 | if (!stralloc_copys(&addr,"T")) die_nomem(fatal); | |
63 | if (!stralloc_cats(&addr,userhost)) die_nomem(fatal); | |
64 | ||
65 | j = byte_rchr(addr.s,addr.len,'@'); | |
66 | if (j == addr.len) return 0; | |
67 | case_lowerb(addr.s + j + 1,addr.len - j - 1); | |
68 | if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal); | |
69 | case_lowerb(lcaddr.s + 1,j - 1); /* totally lc version of addr */ | |
70 | ||
71 | h = 5381; | |
72 | lch = h; /* make hash for both for backwards comp */ | |
73 | for (j = 0;j < addr.len;++j) { /* (lcaddr.len == addr.len) */ | |
74 | h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; | |
75 | lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j]; | |
76 | } | |
77 | ch = 64 + (h % 53); | |
78 | lcch = 64 + (lch % 53); | |
79 | ||
80 | if (!stralloc_0(&addr)) die_nomem(fatal); | |
81 | if (!stralloc_0(&lcaddr)) die_nomem(fatal); | |
82 | if (!stralloc_copys(&fn,dbname)) die_nomem(fatal); | |
83 | if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal); | |
84 | if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal); | |
85 | if (!stralloc_0(&fn)) die_nomem(fatal); | |
86 | ||
87 | fd = open_read(fn.s); | |
88 | if (fd == -1) { | |
89 | if (errno != error_noent) | |
90 | strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); | |
91 | } else { | |
92 | substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); | |
93 | ||
94 | for (;;) { | |
95 | if (getln(&ss,&line,&match,'\0') == -1) | |
96 | strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); | |
97 | if (!match) break; | |
98 | if (line.len == lcaddr.len) | |
99 | if (!case_diffb(line.s,line.len,lcaddr.s)) | |
100 | { close(fd); return line.s+1; } | |
101 | } | |
102 | ||
103 | close(fd); | |
104 | } | |
105 | /* here if file not found or (file found && addr not there) */ | |
106 | ||
107 | if (ch == lcch) return 0; | |
108 | ||
109 | /* try case sensitive hash for backwards compatibility */ | |
110 | fn.s[fn.len - 2] = ch; | |
111 | fd = open_read(fn.s); | |
112 | if (fd == -1) { | |
113 | if (errno != error_noent) | |
114 | strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); | |
115 | return 0; | |
116 | } | |
117 | substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); | |
118 | ||
119 | for (;;) { | |
120 | if (getln(&ss,&line,&match,'\0') == -1) | |
121 | strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); | |
122 | if (!match) break; | |
123 | if (line.len == addr.len) | |
124 | if (!case_diffb(line.s,line.len,addr.s)) | |
125 | { close(fd); return line.s+1; } | |
126 | } | |
127 | ||
128 | close(fd); | |
129 | ||
130 | return 0; | |
131 | } else { /* SQL version */ | |
132 | /* SELECT address FROM list WHERE address = 'userhost' AND hash */ | |
133 | /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */ | |
134 | /* even easier to defeat. Just faking sender to the list name would*/ | |
135 | /* work. Since sender checks for posts are bogus anyway, I don't */ | |
136 | /* know if it's worth the cost of the "WHERE ...". */ | |
137 | ||
138 | if (!stralloc_copys(&addr,userhost)) die_nomem(fatal); | |
139 | j = byte_rchr(addr.s,addr.len,'@'); | |
140 | if (j == addr.len) return 0; | |
141 | case_lowerb(addr.s + j + 1,addr.len - j - 1); | |
142 | ||
143 | if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(fatal); | |
144 | if (!stralloc_cats(&line,table)) die_nomem(fatal); | |
145 | if (!stralloc_cats(&line," WHERE address = '")) die_nomem(fatal); | |
146 | if (!stralloc_ready("ed,2 * addr.len + 1)) die_nomem(fatal); | |
147 | if (!stralloc_catb(&line,quoted.s, | |
148 | mysql_escape_string(quoted.s,userhost,addr.len))) die_nomem(fatal); | |
149 | if (!stralloc_cats(&line,"'")) | |
150 | die_nomem(fatal); | |
151 | if (mysql_real_query((MYSQL *) psql,line.s,line.len)) /* query */ | |
152 | strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); | |
153 | if (!(result = mysql_use_result((MYSQL *) psql))) | |
154 | strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); | |
155 | row = mysql_fetch_row(result); | |
156 | ret = (char *) 0; | |
157 | if (!row) { /* we need to return the actual address as other */ | |
158 | /* dbs may accept user-*@host, but we still want */ | |
159 | /* to make sure to send to e.g the correct moderator*/ | |
160 | /* address. */ | |
161 | if (!mysql_eof(result)) | |
162 | strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); | |
163 | } else { | |
164 | if (!(lengths = mysql_fetch_lengths(result))) | |
165 | strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); | |
166 | if (!stralloc_copyb(&line,row[0],lengths[0])) die_nomem(fatal); | |
167 | if (!stralloc_0(&line)) die_nomem(fatal); | |
168 | ret = line.s; | |
169 | while ((row = mysql_fetch_row(result))); /* maybe not necessary */ | |
170 | mysql_free_result(result); | |
171 | } | |
172 | return ret; | |
173 | } | |
174 | } |