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