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