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