Commit | Line | Data |
---|---|---|
f8beb284 MW |
1 | /*$Id: issub.c,v 1.4 1999/12/11 03:04:03 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 <unistd.h> | |
17 | #include <libpq-fe.h> | |
18 | ||
19 | static void die_nomem(fatal) | |
20 | char *fatal; | |
21 | { | |
22 | strerr_die2x(111,fatal,ERR_NOMEM); | |
23 | } | |
24 | ||
25 | static stralloc addr = {0}; | |
26 | static stralloc lcaddr = {0}; | |
27 | static stralloc line = {0}; | |
28 | static stralloc fn = {0}; | |
29 | static substdio ss; | |
30 | static char ssbuf[512]; | |
31 | ||
32 | char *issub(dbname,userhost,tab,fatal) | |
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 | char *dbname; /* directory to basedir */ | |
39 | char *userhost; | |
40 | char *tab; /* override table name */ | |
41 | char *fatal; | |
42 | ||
43 | { | |
44 | PGresult *result; | |
45 | char *ret; | |
46 | char *table; | |
47 | ||
48 | int fd; | |
49 | unsigned int j; | |
50 | uint32 h,lch; | |
51 | char ch,lcch; | |
52 | int match; | |
53 | ||
54 | table = tab; | |
55 | if ((ret = opensql(dbname,&table))) { | |
56 | if (*ret) strerr_die2x(111,fatal,ret); | |
57 | /* fallback to local db */ | |
58 | ||
59 | if (!stralloc_copys(&addr,"T")) die_nomem(fatal); | |
60 | if (!stralloc_cats(&addr,userhost)) die_nomem(fatal); | |
61 | ||
62 | j = byte_rchr(addr.s,addr.len,'@'); | |
63 | if (j == addr.len) return 0; | |
64 | case_lowerb(addr.s + j + 1,addr.len - j - 1); | |
65 | if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal); | |
66 | case_lowerb(lcaddr.s + 1,j - 1); /* totally lc version of addr */ | |
67 | ||
68 | h = 5381; | |
69 | lch = h; /* make hash for both for backwards comp */ | |
70 | for (j = 0;j < addr.len;++j) { /* (lcaddr.len == addr.len) */ | |
71 | h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; | |
72 | lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j]; | |
73 | } | |
74 | ch = 64 + (h % 53); | |
75 | lcch = 64 + (lch % 53); | |
76 | ||
77 | if (!stralloc_0(&addr)) die_nomem(fatal); | |
78 | if (!stralloc_0(&lcaddr)) die_nomem(fatal); | |
79 | if (!stralloc_copys(&fn,dbname)) die_nomem(fatal); | |
80 | if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal); | |
81 | if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal); | |
82 | if (!stralloc_0(&fn)) die_nomem(fatal); | |
83 | ||
84 | fd = open_read(fn.s); | |
85 | if (fd == -1) { | |
86 | if (errno != error_noent) | |
87 | strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); | |
88 | } else { | |
89 | substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); | |
90 | ||
91 | for (;;) { | |
92 | if (getln(&ss,&line,&match,'\0') == -1) | |
93 | strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); | |
94 | if (!match) break; | |
95 | if (line.len == lcaddr.len) | |
96 | if (!case_diffb(line.s,line.len,lcaddr.s)) | |
97 | { close(fd); return line.s+1; } | |
98 | } | |
99 | ||
100 | close(fd); | |
101 | } | |
102 | /* here if file not found or (file found && addr not there) */ | |
103 | ||
104 | if (ch == lcch) return 0; | |
105 | ||
106 | /* try case sensitive hash for backwards compatibility */ | |
107 | fn.s[fn.len - 2] = ch; | |
108 | fd = open_read(fn.s); | |
109 | if (fd == -1) { | |
110 | if (errno != error_noent) | |
111 | strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); | |
112 | return 0; | |
113 | } | |
114 | substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); | |
115 | ||
116 | for (;;) { | |
117 | if (getln(&ss,&line,&match,'\0') == -1) | |
118 | strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); | |
119 | if (!match) break; | |
120 | if (line.len == addr.len) | |
121 | if (!case_diffb(line.s,line.len,addr.s)) | |
122 | { close(fd); return line.s+1; } | |
123 | } | |
124 | ||
125 | close(fd); | |
126 | ||
127 | return 0; | |
128 | } else { /* SQL version */ | |
129 | /* SELECT address FROM list WHERE address = 'userhost' AND hash */ | |
130 | /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */ | |
131 | /* even easier to defeat. Just faking sender to the list name would*/ | |
132 | /* work. Since sender checks for posts are bogus anyway, I don't */ | |
133 | /* know if it's worth the cost of the "WHERE ...". */ | |
134 | ||
135 | if (!stralloc_copys(&addr,userhost)) die_nomem(fatal); | |
136 | j = byte_rchr(addr.s,addr.len,'@'); | |
137 | if (j == addr.len) return 0; | |
138 | case_lowerb(addr.s + j + 1,addr.len - j - 1); | |
139 | ||
140 | if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(fatal); | |
141 | if (!stralloc_cats(&line,table)) die_nomem(fatal); | |
142 | if (!stralloc_cats(&line," WHERE address ~* '^")) die_nomem(fatal); | |
143 | if (!stralloc_cat(&line,&addr)) die_nomem(fatal); | |
144 | if (!stralloc_cats(&line,"$'")) die_nomem(fatal); | |
145 | ||
146 | if (!stralloc_0(&line)) die_nomem(fatal); | |
147 | result = PQexec(psql,line.s); | |
148 | if (result == NULL) | |
149 | strerr_die2x(111,fatal,PQerrorMessage(psql)); | |
150 | if (PQresultStatus(result) != PGRES_TUPLES_OK ) | |
151 | strerr_die2x(111,fatal,PQresultErrorMessage(result)); | |
152 | ||
153 | /* No data returned in QUERY */ | |
154 | if (PQntuples(result) < 1) | |
155 | return (char *)0; | |
156 | ||
157 | if (!stralloc_copyb(&line,PQgetvalue(result,0,0),PQgetlength(result,0,0))) | |
158 | die_nomem(fatal); | |
159 | if (!stralloc_0(&line)) die_nomem(fatal); | |
160 | ||
161 | PQclear(result); | |
162 | return line.s; | |
163 | } | |
164 | } | |
165 |