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