0
|
1 /* Distributed Checksum Clearinghouse |
|
2 * |
|
3 * build and parse headers |
|
4 * |
|
5 * Copyright (c) 2008 by Rhyolite Software, LLC |
|
6 * |
|
7 * This agreement is not applicable to any entity which sells anti-spam |
|
8 * solutions to others or provides an anti-spam solution as part of a |
|
9 * security solution sold to other entities, or to a private network |
|
10 * which employs the DCC or uses data provided by operation of the DCC |
|
11 * but does not provide corresponding data to other users. |
|
12 * |
|
13 * Permission to use, copy, modify, and distribute this software without |
|
14 * changes for any purpose with or without fee is hereby granted, provided |
|
15 * that the above copyright notice and this permission notice appear in all |
|
16 * copies and any distributed versions or copies are either unchanged |
|
17 * or not called anything similar to "DCC" or "Distributed Checksum |
|
18 * Clearinghouse". |
|
19 * |
|
20 * Parties not eligible to receive a license under this agreement can |
|
21 * obtain a commercial license to use DCC by contacting Rhyolite Software |
|
22 * at sales@rhyolite.com. |
|
23 * |
|
24 * A commercial license would be for Distributed Checksum and Reputation |
|
25 * Clearinghouse software. That software includes additional features. This |
|
26 * free license for Distributed ChecksumClearinghouse Software does not in any |
|
27 * way grant permision to use Distributed Checksum and Reputation Clearinghouse |
|
28 * software |
|
29 * |
|
30 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL |
|
31 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
|
32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC |
|
33 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES |
|
34 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
35 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
36 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
37 * SOFTWARE. |
|
38 * |
|
39 * Rhyolite Software DCC 1.3.103-1.37 $Revision$ |
|
40 */ |
|
41 |
|
42 #include "dcc_clnt.h" |
|
43 #include "dcc_xhdr.h" |
|
44 |
|
45 |
|
46 /* add text to the growing X-DCC header line */ |
|
47 void |
|
48 xhdr_add_str(DCC_HEADER_BUF *hdr, const char *p, ...) |
|
49 { |
|
50 char *hp; |
|
51 u_int lim, n; |
|
52 va_list args; |
|
53 |
|
54 lim = sizeof(hdr->buf) - hdr->used; |
|
55 if (lim <= 0) |
|
56 return; |
|
57 hp = &hdr->buf[hdr->used]; |
|
58 if (*(hp-1) == '\n') { |
|
59 *(hp-1) = ' '; |
|
60 ++hdr->col; |
|
61 } |
|
62 va_start(args, p); |
|
63 n = vsnprintf(hp, lim, p, args); |
|
64 va_end(args); |
|
65 if (n >= lim-3) { |
|
66 dcc_error_msg("header buffer too small"); |
|
67 hdr->buf[lim-1] = '\n'; |
|
68 hdr->used = sizeof(hdr->buf); |
|
69 return; |
|
70 } |
|
71 hdr->col += n; |
|
72 hp[n++] = '\n'; |
|
73 hp[n] = '\0'; |
|
74 hdr->used += n; |
|
75 |
|
76 /* follow RFC 2822 and limit lines to 78 */ |
|
77 if (hdr->col > DCC_MAX_HDR_LINE /* if pushed past line end, */ |
|
78 && *(hp-1) == ' ' /* & not the first cksum report, */ |
|
79 && hdr->used < sizeof(hdr->buf)-2) { /* & have space */ |
|
80 memmove(hp+1, hp, n+1); /* then break the line */ |
|
81 *(hp-1) = '\n'; |
|
82 *hp = '\t'; |
|
83 hdr->col = n+8; |
|
84 ++hdr->used; |
|
85 } |
|
86 } |
|
87 |
|
88 |
|
89 |
|
90 /* generate X-DCC field name */ |
|
91 int /* bytes put into buffer */ |
|
92 get_xhdr_fname(char *xhdr, int xhdr_len, const DCC_CLNT_INFO *info) |
|
93 { |
|
94 SRVR_INX srvr_inx; |
|
95 const char *brand; |
|
96 int i; |
|
97 |
|
98 if (!info |
|
99 || !GOOD_SRVR(&info->dcc, srvr_inx = info->dcc.srvr_inx)) { |
|
100 brand = ""; |
|
101 i = 0; |
|
102 } else { |
|
103 brand = info->dcc.addrs[srvr_inx].brand; |
|
104 i = xhdr_len-sizeof(DCC_XHDR_START); |
|
105 if (i < 0) |
|
106 i = 0; |
|
107 if (i > ISZ(DCC_BRAND)) |
|
108 i = ISZ(DCC_BRAND); |
|
109 } |
|
110 |
|
111 i = snprintf(xhdr, xhdr_len, DCC_XHDR_PAT, i, brand); |
|
112 if (i >= xhdr_len) |
|
113 i = xhdr_len-1; |
|
114 return i; |
|
115 } |
|
116 |
|
117 |
|
118 |
|
119 /* get ready to generate an X-DCC header including generating the |
|
120 * field name */ |
|
121 void |
|
122 xhdr_init(DCC_HEADER_BUF *hdr, DCC_SRVR_ID srvr_id) |
|
123 { |
|
124 if (srvr_id < DCC_SRVR_ID_MIN || srvr_id > DCC_SRVR_ID_MAX) { |
|
125 hdr->used = get_xhdr_fname(hdr->buf, sizeof(hdr->buf)-8, |
|
126 0); |
|
127 } else { |
|
128 hdr->used = get_xhdr_fname(hdr->buf, sizeof(hdr->buf)-8, |
|
129 dcc_clnt_info); |
|
130 } |
|
131 hdr->col = hdr->used; |
|
132 hdr->start_len = hdr->used; |
|
133 |
|
134 xhdr_add_str(hdr, ": %s %d;", dcc_clnt_hostname, srvr_id); |
|
135 } |
|
136 |
|
137 |
|
138 |
|
139 /* add a checksum and its counts to a growing X-DCC-Warning header line */ |
|
140 void |
|
141 xhdr_add_ck(DCC_HEADER_BUF *hdr, |
|
142 DCC_CK_TYPES type, /* which kind of checksum */ |
|
143 DCC_TGTS tgts) |
|
144 { |
|
145 char tbuf[30], ckcnt[10]; |
|
146 |
|
147 xhdr_add_str(hdr, "%s=%s", |
|
148 dcc_type2str(tbuf, sizeof(tbuf), type, 0, 0, 0), |
|
149 dcc_tgts2str(ckcnt, sizeof(ckcnt), tgts, 0)); |
|
150 } |
|
151 |
|
152 |
|
153 |
|
154 /* write header with lines ending with either "\n" or "\r\n" |
|
155 * the buffer must already contain '\n' as needed */ |
|
156 void |
|
157 xhdr_write(LOG_WRITE_FNC fnc, void *wctxt, |
|
158 const char *hdr, int hdr_len, |
|
159 u_char crlf) /* 1=use "\r\n" instead of "\n" */ |
|
160 { |
|
161 char c; |
|
162 int i; |
|
163 |
|
164 if (hdr_len == 0) |
|
165 return; |
|
166 |
|
167 i = 0; |
|
168 for (;;) { |
|
169 c = hdr[i]; |
|
170 if (c == '\n' && crlf) { |
|
171 if (i != 0) |
|
172 fnc(wctxt, hdr, i); |
|
173 fnc(wctxt, "\r\n", 2); |
|
174 ++i; |
|
175 hdr += i; |
|
176 hdr_len -= i; |
|
177 if (hdr_len <= 0) |
|
178 return; |
|
179 i = 0; |
|
180 continue; |
|
181 } |
|
182 if (++i >= hdr_len) { |
|
183 fnc(wctxt, hdr, i); |
|
184 return; |
|
185 } |
|
186 } |
|
187 } |
|
188 |
|
189 |
|
190 |
|
191 /* create a special X-DCC header for a whitelist mail message |
|
192 * it lacks a DCC server-ID because there is none and to let |
|
193 * DCC clients distinguish it from real X-DCC headers */ |
|
194 void |
|
195 xhdr_whitelist(DCC_HEADER_BUF *hdr) |
|
196 { |
|
197 hdr->col = 0; |
|
198 hdr->start_len = 0; |
|
199 hdr->used = 0; |
|
200 xhdr_add_str(hdr, DCC_XHDR_START DCC_XHDR_END": %s; "DCC_XHDR_WHITELIST, |
|
201 dcc_clnt_hostname); |
|
202 } |
|
203 |
|
204 |
|
205 |
|
206 /* see if an X-DCC header looks like one of our own and so should |
|
207 * be deleted */ |
|
208 u_char /* 1=is an X-DCC-...-metrics header */ |
|
209 is_xhdr(const char *buf, /* complete header */ |
|
210 int buf_len) |
|
211 { |
|
212 const char *e; |
|
213 |
|
214 if (buf[0] != 'X' && buf[0] != 'x') |
|
215 return 0; |
|
216 if (buf_len <= LITZ(DCC_XHDR_START DCC_XHDR_END":") |
|
217 || CLITCMP(buf, DCC_XHDR_START)) |
|
218 return 0; |
|
219 |
|
220 buf += LITZ(DCC_XHDR_START); |
|
221 buf_len -= LITZ(DCC_XHDR_START); |
|
222 |
|
223 /* look for the end of header field name */ |
|
224 e = memchr(buf, ':', buf_len); |
|
225 if (e) { |
|
226 buf_len = e - buf; |
|
227 if (buf_len < LITZ(DCC_XHDR_END)) |
|
228 return 0; |
|
229 } |
|
230 |
|
231 buf_len -= LITZ(DCC_XHDR_END); |
|
232 buf += buf_len; |
|
233 if (!CLITCMP(buf, DCC_XHDR_END)) |
|
234 return 1; |
|
235 |
|
236 return 0; |
|
237 } |