]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfcnb/rfcnb-io.c
Simplified MSNT basic auth helper
[thirdparty/squid.git] / lib / rfcnb / rfcnb-io.c
1 /*
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
10 *
11 * Version 1.0
12 * RFCNB IO Routines ...
13 *
14 * Copyright (C) Richard Sharpe 1996
15 */
16
17 /*
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 */
32
33 #include "squid.h"
34 #include "rfcnb/rfcnb-io.h"
35 #include "rfcnb/rfcnb-priv.h"
36 #include "rfcnb/rfcnb-util.h"
37 #include "rfcnb/std-includes.h"
38
39 #if HAVE_STRING_H
40 #include <string.h>
41 #endif
42 #include <sys/uio.h>
43 #include <sys/signal.h>
44
45 int RFCNB_Timeout = 0; /* Timeout in seconds ... */
46
47 static int RFCNB_Discard_Rest(struct RFCNB_Con *con, int len);
48
49 #ifdef NOT_USED
50 void
51 rfcnb_alarm(int sig)
52 {
53
54 fprintf(stderr, "IO Timed out ...\n");
55
56 }
57
58 #endif /* NOT_USED */
59
60 #ifdef NOT_USED
61 /* Set timeout value and setup signal handling */
62 int
63 RFCNB_Set_Timeout(int seconds)
64 {
65 /* If we are on a Bezerkeley system, use sigvec, else sigaction */
66
67 #if ORIGINAL_SAMBA_CODE
68 #ifndef SA_RESTART
69 struct sigvec invec, outvec;
70 #else
71 struct sigaction inact, outact;
72 #endif
73
74 RFCNB_Timeout = seconds;
75
76 if (RFCNB_Timeout > 0) { /* Set up handler to ignore but not restart */
77
78 #ifndef SA_RESTART
79 invec.sv_handler = (void (*)()) rfcnb_alarm;
80 invec.sv_mask = 0;
81 invec.sv_flags = SV_INTERRUPT;
82
83 if (sigvec(SIGALRM, &invec, &outvec) < 0)
84 return (-1);
85 #else /* !SA_RESTART */
86 inact.sa_handler = (void (*)()) rfcnb_alarm;
87 #ifdef Solaris
88 /* Solaris seems to have an array of vectors ... */
89 inact.sa_mask.__sigbits[0] = 0;
90 inact.sa_mask.__sigbits[1] = 0;
91 inact.sa_mask.__sigbits[2] = 0;
92 inact.sa_mask.__sigbits[3] = 0;
93 #else /* !Solaris */
94 inact.sa_mask = (sigset_t) 0;
95 #endif /* Solaris */
96 inact.sa_flags = 0; /* Don't restart */
97
98 if (sigaction(SIGALRM, &inact, &outact) < 0)
99 return (-1);
100
101 #endif /* !SA_RESTART */
102
103 }
104 #else /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
105 #if HAVE_SIGACTION
106 struct sigaction inact, outact;
107 #else
108 struct sigvec invec, outvec;
109 #endif
110
111 RFCNB_Timeout = seconds;
112
113 if (RFCNB_Timeout > 0) { /* Set up handler to ignore but not restart */
114
115 #if HAVE_SIGACTION
116 inact.sa_handler = (void (*)()) rfcnb_alarm;
117 sigemptyset(&inact.sa_mask);
118 inact.sa_flags = 0; /* Don't restart */
119
120 if (sigaction(SIGALRM, &inact, &outact) < 0)
121 return (-1);
122 #else /* !HAVE_SIGACTION */
123 invec.sv_handler = (void (*)()) rfcnb_alarm;
124 invec.sv_mask = 0;
125 invec.sv_flags = SV_INTERRUPT;
126
127 if (sigvec(SIGALRM, &invec, &outvec) < 0)
128 return (-1);
129 #endif /* !HAVE_SIGACTION */
130 }
131 #endif /* !ORIGINAL_SAMBA_CODE ADAPTED SQUID CODE */
132 return (0);
133 }
134 #endif /* NOT_USED */
135
136 /* Discard the rest of an incoming packet as we do not have space for it
137 * in the buffer we allocated or were passed ... */
138
139 int
140 RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
141 {
142 char temp[100]; /* Read into here */
143 int rest, this_read, bytes_read;
144
145 /* len is the amount we should read */
146
147 #ifdef RFCNB_DEBUG
148 fprintf(stderr, "Discard_Rest called to discard: %i\n", len);
149 #endif
150
151 rest = len;
152
153 while (rest > 0) {
154
155 this_read = (rest > sizeof(temp) ? sizeof(temp) : rest);
156
157 bytes_read = read(con->fd, temp, this_read);
158
159 if (bytes_read <= 0) { /* Error so return */
160
161 if (bytes_read < 0)
162 RFCNB_errno = RFCNBE_BadRead;
163 else
164 RFCNB_errno = RFCNBE_ConGone;
165
166 RFCNB_saved_errno = errno;
167 return (RFCNBE_Bad);
168
169 }
170 rest = rest - bytes_read;
171
172 }
173
174 return (0);
175
176 }
177
178 /* Send an RFCNB packet to the connection.
179 *
180 * We just send each of the blocks linked together ...
181 *
182 * If we can, try to send it as one iovec ...
183 *
184 */
185
186 int
187 RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
188 {
189 int len_sent, tot_sent, this_len;
190 struct RFCNB_Pkt *pkt_ptr;
191 char *this_data;
192 int i;
193 struct iovec io_list[10]; /* We should never have more */
194 /* If we do, this will blow up ... */
195
196 /* Try to send the data ... We only send as many bytes as len claims */
197 /* We should try to stuff it into an IOVEC and send as one write */
198
199 pkt_ptr = pkt;
200 len_sent = tot_sent = 0; /* Nothing sent so far */
201 i = 0;
202
203 while ((pkt_ptr != NULL) & (i < 10)) { /* Watch that magic number! */
204
205 this_len = pkt_ptr->len;
206 this_data = pkt_ptr->data;
207 if ((tot_sent + this_len) > len)
208 this_len = len - tot_sent; /* Adjust so we don't send too much */
209
210 /* Now plug into the iovec ... */
211
212 io_list[i].iov_len = this_len;
213 io_list[i].iov_base = this_data;
214 i++;
215
216 tot_sent += this_len;
217
218 if (tot_sent == len)
219 break; /* Let's not send too much */
220
221 pkt_ptr = pkt_ptr->next;
222
223 }
224
225 #ifdef RFCNB_DEBUG
226 fprintf(stderr, "Frags = %i, tot_sent = %i\n", i, tot_sent);
227 #endif
228
229 /* Set up an alarm if timeouts are set ... */
230
231 if (RFCNB_Timeout > 0)
232 alarm(RFCNB_Timeout);
233
234 if ((len_sent = writev(con->fd, io_list, i)) < 0) { /* An error */
235
236 con->errn = errno;
237 if (errno == EINTR) /* We were interrupted ... */
238 RFCNB_errno = RFCNBE_Timeout;
239 else
240 RFCNB_errno = RFCNBE_BadWrite;
241 RFCNB_saved_errno = errno;
242 return (RFCNBE_Bad);
243
244 }
245 if (len_sent < tot_sent) { /* Less than we wanted */
246 if (errno == EINTR) /* We were interrupted */
247 RFCNB_errno = RFCNBE_Timeout;
248 else
249 RFCNB_errno = RFCNBE_BadWrite;
250 RFCNB_saved_errno = errno;
251 return (RFCNBE_Bad);
252 }
253 if (RFCNB_Timeout > 0)
254 alarm(0); /* Reset that sucker */
255
256 #ifdef RFCNB_DEBUG
257
258 fprintf(stderr, "Len sent = %i ...\n", len_sent);
259 RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent); /* Print what send ... */
260
261 #endif
262
263 return (len_sent);
264
265 }
266
267 /* Read an RFCNB packet off the connection.
268 *
269 * We read the first 4 bytes, that tells us the length, then read the
270 * rest. We should implement a timeout, but we don't just yet
271 *
272 */
273
274 int
275 RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
276 {
277 int read_len, pkt_len;
278 char hdr[RFCNB_Pkt_Hdr_Len]; /* Local space for the header */
279 struct RFCNB_Pkt *pkt_frag;
280 int more, this_time, offset, frag_len, this_len;
281 BOOL seen_keep_alive = TRUE;
282
283 /* Read that header straight into the buffer */
284
285 if (len < RFCNB_Pkt_Hdr_Len) { /* What a bozo */
286
287 #ifdef RFCNB_DEBUG
288 fprintf(stderr, "Trying to read less than a packet:");
289 perror("");
290 #endif
291 RFCNB_errno = RFCNBE_BadParam;
292 return (RFCNBE_Bad);
293
294 }
295 /* We discard keep alives here ... */
296
297 if (RFCNB_Timeout > 0)
298 alarm(RFCNB_Timeout);
299
300 while (seen_keep_alive) {
301
302 if ((read_len = read(con->fd, hdr, sizeof(hdr))) < 0) { /* Problems */
303 #ifdef RFCNB_DEBUG
304 fprintf(stderr, "Reading the packet, we got:");
305 perror("");
306 #endif
307 if (errno == EINTR)
308 RFCNB_errno = RFCNBE_Timeout;
309 else
310 RFCNB_errno = RFCNBE_BadRead;
311 RFCNB_saved_errno = errno;
312 return (RFCNBE_Bad);
313
314 }
315 /* Now we check out what we got */
316
317 if (read_len == 0) { /* Connection closed, send back eof? */
318
319 #ifdef RFCNB_DEBUG
320 fprintf(stderr, "Connection closed reading\n");
321 #endif
322
323 if (errno == EINTR)
324 RFCNB_errno = RFCNBE_Timeout;
325 else
326 RFCNB_errno = RFCNBE_ConGone;
327 RFCNB_saved_errno = errno;
328 return (RFCNBE_Bad);
329
330 }
331 if (RFCNB_Pkt_Type(hdr) == RFCNB_SESSION_KEEP_ALIVE) {
332
333 #ifdef RFCNB_DEBUG
334 fprintf(stderr, "RFCNB KEEP ALIVE received\n");
335 #endif
336
337 } else {
338 seen_keep_alive = FALSE;
339 }
340
341 }
342
343 /* What if we got less than or equal to a hdr size in bytes? */
344
345 if (read_len < sizeof(hdr)) { /* We got a small packet */
346
347 /* Now we need to copy the hdr portion we got into the supplied packet */
348
349 memcpy(pkt->data, hdr, read_len); /*Copy data */
350
351 #ifdef RFCNB_DEBUG
352 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
353 #endif
354
355 return (read_len);
356
357 }
358 /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
359
360 pkt_len = RFCNB_Pkt_Len(hdr);
361
362 #ifdef RFCNB_DEBUG
363 fprintf(stderr, "Reading Pkt: Length = %i\n", pkt_len);
364 #endif
365
366 /* Now copy in the hdr */
367
368 memcpy(pkt->data, hdr, sizeof(hdr));
369
370 /* Get the rest of the packet ... first figure out how big our buf is? */
371 /* And make sure that we handle the fragments properly ... Sure should */
372 /* use an iovec ... */
373
374 if (len < pkt_len) /* Only get as much as we have space for */
375 more = len - RFCNB_Pkt_Hdr_Len;
376 else
377 more = pkt_len;
378
379 this_time = 0;
380
381 /* We read for each fragment ... */
382
383 if (pkt->len == read_len) { /* If this frag was exact size */
384 pkt_frag = pkt->next; /* Stick next lot in next frag */
385 offset = 0; /* then we start at 0 in next */
386 } else {
387 pkt_frag = pkt; /* Otherwise use rest of this frag */
388 offset = RFCNB_Pkt_Hdr_Len; /* Otherwise skip the header */
389 }
390
391 frag_len = (pkt_frag ? pkt_frag->len : 0);
392
393 if (more <= frag_len) /* If len left to get less than frag space */
394 this_len = more; /* Get the rest ... */
395 else
396 this_len = frag_len - offset;
397
398 while (more > 0) {
399
400 if ((this_time = read(con->fd, (pkt_frag->data) + offset, this_len)) <= 0) { /* Problems */
401
402 if (errno == EINTR) {
403
404 RFCNB_errno = RFCNB_Timeout;
405
406 } else {
407 if (this_time < 0)
408 RFCNB_errno = RFCNBE_BadRead;
409 else
410 RFCNB_errno = RFCNBE_ConGone;
411 }
412
413 RFCNB_saved_errno = errno;
414 return (RFCNBE_Bad);
415
416 }
417 #ifdef RFCNB_DEBUG
418 fprintf(stderr, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len,
419 this_time, this_len, more);
420 #endif
421
422 read_len = read_len + this_time; /* How much have we read ... */
423
424 /* Now set up the next part */
425
426 if (pkt_frag->next == NULL)
427 break; /* That's it here */
428
429 pkt_frag = pkt_frag->next;
430 this_len = pkt_frag->len;
431 offset = 0;
432
433 more = more - this_time;
434
435 }
436
437 #ifdef RFCNB_DEBUG
438 fprintf(stderr, "Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
439 RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
440 #endif
441
442 if (read_len < (pkt_len + sizeof(hdr))) { /* Discard the rest */
443
444 return (RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
445
446 }
447 if (RFCNB_Timeout > 0)
448 alarm(0); /* Reset that sucker */
449
450 return (read_len + sizeof(RFCNB_Hdr));
451 }
452