0
|
1 /* Distributed Checksum Clearinghouse |
|
2 * |
|
3 * Copyright (c) 2008 by Rhyolite Software, LLC |
|
4 * |
|
5 * This agreement is not applicable to any entity which sells anti-spam |
|
6 * solutions to others or provides an anti-spam solution as part of a |
|
7 * security solution sold to other entities, or to a private network |
|
8 * which employs the DCC or uses data provided by operation of the DCC |
|
9 * but does not provide corresponding data to other users. |
|
10 * |
|
11 * Permission to use, copy, modify, and distribute this software without |
|
12 * changes for any purpose with or without fee is hereby granted, provided |
|
13 * that the above copyright notice and this permission notice appear in all |
|
14 * copies and any distributed versions or copies are either unchanged |
|
15 * or not called anything similar to "DCC" or "Distributed Checksum |
|
16 * Clearinghouse". |
|
17 * |
|
18 * Parties not eligible to receive a license under this agreement can |
|
19 * obtain a commercial license to use DCC by contacting Rhyolite Software |
|
20 * at sales@rhyolite.com. |
|
21 * |
|
22 * A commercial license would be for Distributed Checksum and Reputation |
|
23 * Clearinghouse software. That software includes additional features. This |
|
24 * free license for Distributed ChecksumClearinghouse Software does not in any |
|
25 * way grant permision to use Distributed Checksum and Reputation Clearinghouse |
|
26 * software |
|
27 * |
|
28 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL |
|
29 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
|
30 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC |
|
31 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES |
|
32 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
33 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
34 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
35 * SOFTWARE. |
|
36 * |
|
37 * Rhyolite Software DCC 1.3.103-1.47 $Revision$ |
|
38 */ |
|
39 |
|
40 #include "dcc_clnt.h" |
|
41 |
|
42 |
|
43 /* open a file of server names, ports, and so forth */ |
|
44 FILE * |
|
45 dcc_open_srvr_nm(DCC_EMSG emsg, const char *nm) |
|
46 { |
|
47 FILE *f; |
|
48 DCC_PATH path; |
|
49 |
|
50 f = fopen(nm, "r"); |
|
51 if (!f) { |
|
52 dcc_pemsg(EX_NOINPUT, emsg, |
|
53 "fopen(%s): %s", fnm2abs_err(path, nm), ERROR_STR()); |
|
54 return 0; |
|
55 } |
|
56 |
|
57 /* the file contains passwords, |
|
58 * so refuse to use it if everyone can read it */ |
|
59 if (!dcc_ck_private(emsg, 0, nm, fileno(f))) { |
|
60 fclose(f); |
|
61 return 0; |
|
62 } |
|
63 return f; |
|
64 } |
|
65 |
|
66 |
|
67 |
|
68 /* get "hostname,port" string from the start of a line */ |
|
69 const char * /* 0=bad, rest of line if ok */ |
|
70 dcc_parse_nm_port(DCC_EMSG emsg, |
|
71 const char *line0, |
|
72 u_int def_port, /* default or DCC_GET_PORT_INVALID */ |
|
73 char *hostname, /* put host name here */ |
|
74 u_int hostname_len, |
|
75 u_int16_t *portp, /* put port # in network byte order */ |
|
76 char *portname, /* put port name here */ |
|
77 u_int portname_len, |
|
78 const char *fnm, int lno) /* configuration file source */ |
|
79 { |
|
80 DCC_FNM_LNO_BUF fnm_buf; |
|
81 char buf[DCC_MAXDOMAINLEN+1+MAXPORTNAMELEN+1]; /* "name,#\0" */ |
|
82 const char *line; |
|
83 const char *pstr; |
|
84 u_int port; |
|
85 u_int hlen; |
|
86 |
|
87 |
|
88 /* get both parameters */ |
|
89 line = dcc_parse_word(emsg, buf, sizeof(buf), line0, |
|
90 "hostname,port", fnm, lno); |
|
91 if (!line) |
|
92 return 0; |
|
93 |
|
94 /* get the hostname and separate the port number */ |
|
95 pstr = strchr(buf, ','); |
|
96 if (!pstr) { |
|
97 if (def_port == DCC_GET_PORT_INVALID) { |
|
98 dcc_pemsg(EX_USAGE, emsg, "missing port in \"%s\"%s", |
|
99 buf, fnm_lno(&fnm_buf, fnm, lno)); |
|
100 return 0; |
|
101 } |
|
102 hlen = strlen(buf); |
|
103 pstr = "-"; |
|
104 } else { |
|
105 hlen = pstr++ - buf; |
|
106 } |
|
107 |
|
108 if (hostname_len) { |
|
109 memset(hostname, 0, hostname_len); |
|
110 if (hlen >= hostname_len) { |
|
111 dcc_pemsg(EX_NOHOST, emsg, |
|
112 "hostname \"%.16s...\" too long%s", |
|
113 buf, fnm_lno(&fnm_buf, fnm, lno)); |
|
114 return 0; |
|
115 } |
|
116 if (hlen) |
|
117 memcpy(hostname, buf, hlen); |
|
118 } |
|
119 if (portname_len) { |
|
120 memset(portname, 0, portname_len); |
|
121 hlen = strlen(pstr); |
|
122 if (hlen >= portname_len) |
|
123 hlen = portname_len-1; |
|
124 if (hlen) |
|
125 memcpy(portname, pstr, hlen); |
|
126 } |
|
127 |
|
128 /* get the port number */ |
|
129 port = dcc_get_port(emsg, pstr, def_port, fnm, lno); |
|
130 if (port == DCC_GET_PORT_INVALID) |
|
131 return 0; |
|
132 |
|
133 if (portp) |
|
134 *portp = port; |
|
135 return line; |
|
136 } |
|
137 |
|
138 |
|
139 |
|
140 /* parse a line of the following form |
|
141 * hostname[,port-#] [RTT+adj] [Greylist] [client-ID [password]] |
|
142 * The port-# can be "-" to specifiy the default DCC server port. |
|
143 * If both the client-ID and the password are absent, then the anonymous |
|
144 * client-ID is used. |
|
145 * A null string is assumed if the password is missing. |
|
146 */ |
|
147 int /* 1=parsed, 0=bad, -1=unknown name */ |
|
148 dcc_parse_srvr_nm(DCC_EMSG emsg, |
|
149 DCC_SRVR_NM *nmp, /* build this entry */ |
|
150 u_char *pgrey, /* 1=for greylisting */ |
|
151 const char *line, /* from this string */ |
|
152 const char *fnm, int lno) /* that came from here */ |
|
153 { |
|
154 DCC_FNM_LNO_BUF fnm_buf; |
|
155 char id_buf[12]; |
|
156 char port_buf[3]; |
|
157 char *p; |
|
158 long l; |
|
159 |
|
160 memset(nmp, 0, sizeof(DCC_SRVR_NM)); |
|
161 |
|
162 line = dcc_parse_nm_port(emsg, line, DCC_GREY2PORT(pgrey && *pgrey), |
|
163 nmp->hostname, sizeof(nmp->hostname), |
|
164 &nmp->port, port_buf, sizeof(port_buf), |
|
165 fnm, lno); |
|
166 if (!line) |
|
167 return 0; |
|
168 |
|
169 for (;;) { |
|
170 /* look for greylist flag */ |
|
171 if (!CLITCMP(line, "greylist") |
|
172 && (line[LITZ("greylist")] == '\0' |
|
173 || line[LITZ("greylist")] == ' ' |
|
174 || line[LITZ("greylist")] == '\t')) { |
|
175 line += LITZ("greylist")+strspn(line+LITZ("greylist"), |
|
176 DCC_WHITESPACE); |
|
177 if (pgrey) |
|
178 *pgrey = 1; |
|
179 if (port_buf[0] == '\0' || !strcmp(port_buf, "-")) |
|
180 nmp->port = htons(DCC_GREY_PORT); |
|
181 continue; |
|
182 } |
|
183 |
|
184 /* look for optional RTT adjustment */ |
|
185 if (CLITCMP(line, "rtt")) |
|
186 break; |
|
187 line += LITZ("rtt")+strspn(line+LITZ("rtt"), DCC_WHITESPACE); |
|
188 l = strtol(line, &p, 10); |
|
189 if (p != line) { |
|
190 int wsp = strspn(p, DCC_WHITESPACE); |
|
191 if (!CLITCMP(p+wsp, "ms")) |
|
192 p += wsp+LITZ("ms"); |
|
193 } |
|
194 if (p == line |
|
195 || (*p != '\0' && *p != ' ' && *p != '\t')) { |
|
196 dcc_pemsg(EX_DATAERR, emsg, |
|
197 "invalid RTT adjustment%s", |
|
198 fnm_lno(&fnm_buf, fnm, lno)); |
|
199 return 0; |
|
200 } |
|
201 if (l < -DCC_RTT_ADJ_MAX/1000) { |
|
202 l = -DCC_RTT_ADJ_MAX/1000; |
|
203 } else if (l > DCC_RTT_ADJ_MAX/1000) { |
|
204 l = DCC_RTT_ADJ_MAX/1000; |
|
205 } |
|
206 nmp->rtt_adj = l*1000; |
|
207 line = p+strspn(p, DCC_WHITESPACE); |
|
208 } |
|
209 |
|
210 /* get the client-ID */ |
|
211 line = dcc_parse_word(emsg, id_buf, sizeof(id_buf), |
|
212 line, "client-ID", fnm, lno); |
|
213 if (!line) |
|
214 return 0; |
|
215 if (id_buf[0] == '\0') { |
|
216 nmp->clnt_id = DCC_ID_ANON; |
|
217 } else { |
|
218 nmp->clnt_id = dcc_get_id(emsg, id_buf, fnm, lno); |
|
219 if (nmp->clnt_id == DCC_ID_INVALID) |
|
220 return 0; |
|
221 if (nmp->clnt_id < DCC_CLNT_ID_MIN |
|
222 && nmp->clnt_id != DCC_ID_ANON) { |
|
223 dcc_pemsg(EX_DATAERR, emsg, |
|
224 "server-ID %d is not a client-ID", |
|
225 nmp->clnt_id); |
|
226 return 0; |
|
227 } |
|
228 } |
|
229 |
|
230 /* allow null password only for anonymous clients |
|
231 * clients of greylist servers cannot be anonymous */ |
|
232 if (nmp->clnt_id == DCC_ID_ANON) { |
|
233 if (*line != '\0') { |
|
234 dcc_pemsg(EX_DATAERR, emsg, |
|
235 "password invalid for %s" |
|
236 " with anonymous client-ID%s", |
|
237 nmp->hostname, |
|
238 fnm_lno(&fnm_buf, fnm, lno)); |
|
239 return 0; |
|
240 } |
|
241 return 1; |
|
242 } |
|
243 |
|
244 if (*line == '\0') { |
|
245 dcc_pemsg(EX_DATAERR, emsg, |
|
246 "invalid null password for client-ID %d for %s%s", |
|
247 nmp->clnt_id, nmp->hostname, |
|
248 fnm_lno(&fnm_buf, fnm, lno)); |
|
249 return 0; |
|
250 } |
|
251 |
|
252 line = parse_passwd(emsg, nmp->passwd, line, "passwd", fnm, lno); |
|
253 if (!line) |
|
254 return 0; |
|
255 if (nmp->passwd[0] == '\0' || *line != '\0') { |
|
256 dcc_pemsg(EX_DATAERR, emsg, |
|
257 "invalid password server %s, client-ID %d%s", |
|
258 nmp->hostname, nmp->clnt_id, |
|
259 fnm_lno(&fnm_buf, fnm, lno)); |
|
260 return 0; |
|
261 } |
|
262 |
|
263 return 1; |
|
264 } |