import from HEAD
[freeradius.git] / src / modules / rlm_smb / rfcnb-util.c
1 /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
2
3    Version 1.0
4    RFCNB Utility 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
26 #include <string.h>
27
28 #include "std-includes.h"
29 #include "rfcnb-priv.h"
30 #include "rfcnb-util.h"
31 #include "rfcnb-io.h"
32
33 extern void (*Prot_Print_Routine)(); /* Pointer to protocol print routine */
34
35 /* Convert name and pad to 16 chars as needed */
36 /* Name 1 is a C string with null termination, name 2 may not be */
37 /* If SysName is true, then put a <00> on end, else space>       */
38
39 void RFCNB_CvtPad_Name(char *name1, char *name2)
40
41 { char c, c1, c2;
42   int i, len;
43
44   len = strlen(name1);
45
46   for (i = 0; i < 16; i++) {
47
48     if (i >= len) {
49
50      c1 = 'C'; c2 = 'A'; /* CA is a space */
51
52     } else {
53
54       c = name1[i];
55       c1 = (char)((int)c/16 + (int)'A');
56       c2 = (char)((int)c%16 + (int)'A');
57     }
58
59     name2[i*2] = c1;
60     name2[i*2+1] = c2;
61
62   }
63
64   name2[32] = 0;   /* Put in the nll ...*/
65
66 }
67
68 /* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
69    Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
70    to produce the next byte in the name.
71
72    This routine assumes that AName is 16 bytes long and that NBName has
73    space for 32 chars, so be careful ...
74
75 */
76
77 void RFCNB_AName_To_NBName(char *AName, char *NBName)
78
79 { char c, c1, c2;
80   int i;
81
82   for (i=0; i < 16; i++) {
83
84     c = AName[i];
85
86     c1 = (char)((c >> 4) + 'A');
87     c2 = (char)((c & 0xF) + 'A');
88
89     NBName[i*2] = c1;
90     NBName[i*2+1] = c2;
91   }
92
93   NBName[32] = 0; /* Put in a null */
94
95 }
96
97 /* Do the reverse of the above ... */
98
99 void RFCNB_NBName_To_AName(char *NBName, char *AName)
100
101 { char c, c1, c2;
102   int i;
103
104   for (i=0; i < 16; i++) {
105
106     c1 = NBName[i*2];
107     c2 = NBName[i*2+1];
108
109     c = (char)(((int)c1 - (int)'A') * 16 + ((int)c2 - (int)'A'));
110
111     AName[i] = c;
112
113   }
114
115   AName[i] = 0;   /* Put a null on the end ... */
116
117 }
118
119 /* Print a string of bytes in HEX etc */
120
121 void RFCNB_Print_Hex(FILE *fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
122
123 { char c1, c2, outbuf1[33];
124   unsigned char c;
125   int i, j;
126   struct RFCNB_Pkt *pkt_ptr = pkt;
127   static char Hex_List[17] = "0123456789ABCDEF";
128
129   j = 0;
130
131   /* We only want to print as much as sepcified in Len */
132
133   while (pkt_ptr != NULL) {
134
135     for (i = 0;
136          i < ((Len > (pkt_ptr -> len)?pkt_ptr -> len:Len) - Offset);
137          i++) {
138
139       c = pkt_ptr -> data[i + Offset];
140       c1 = Hex_List[c >> 4];
141       c2 = Hex_List[c & 0xF];
142
143       outbuf1[j++] = c1; outbuf1[j++] = c2;
144
145       if (j == 32){ /* Print and reset */
146         outbuf1[j] = 0;
147         fprintf(fd, "    %s\n", outbuf1);
148         j = 0;
149       }
150
151     }
152
153     Offset = 0;
154     Len = Len - pkt_ptr -> len;   /* Reduce amount by this much */
155     pkt_ptr = pkt_ptr -> next;
156
157   }
158
159   /* Print last lot in the buffer ... */
160
161   if (j > 0) {
162
163     outbuf1[j] = 0;
164     fprintf(fd, "    %s\n", outbuf1);
165
166   }
167
168   fprintf(fd, "\n");
169
170 }
171
172 /* Get a packet of size n */
173
174 struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
175
176 { RFCNB_Pkt *pkt;
177
178   if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
179
180     RFCNB_errno = RFCNBE_NoSpace;
181     RFCNB_saved_errno = errno;
182     return(NULL);
183
184   }
185
186   pkt -> next = NULL;
187   pkt -> len = n;
188
189   if (n == 0) return(pkt);
190
191   if ((pkt -> data = (char *)malloc(n)) == NULL) {
192
193     RFCNB_errno = RFCNBE_NoSpace;
194     RFCNB_saved_errno = errno;
195     free(pkt);
196     return(NULL);
197
198   }
199
200   return(pkt);
201
202 }
203
204 /* Free up a packet */
205
206 int RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
207
208 { struct RFCNB_Pkt *pkt_next; char *data_ptr;
209
210   while (pkt != NULL) {
211
212     pkt_next = pkt -> next;
213
214     data_ptr = pkt -> data;
215
216     if (data_ptr != NULL)
217       free(data_ptr);
218
219     free(pkt);
220
221     pkt = pkt_next;
222
223   }
224
225 }
226
227 /* Print an RFCNB packet */
228
229 void RFCNB_Print_Pkt(FILE *fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
230
231 { char lname[17];
232
233   /* We assume that the first fragment is the RFCNB Header  */
234   /* We should loop through the fragments printing them out */
235
236   fprintf(fd, "RFCNB Pkt %s:", dirn);
237
238   switch (RFCNB_Pkt_Type(pkt -> data)) {
239
240   case RFCNB_SESSION_MESSAGE:
241
242     fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt -> data));
243     RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len,
244 #ifdef RFCNB_PRINT_DATA
245                     RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len);
246 #else
247                     40);
248 #endif
249
250   if (Prot_Print_Routine != 0) { /* Print the rest of the packet */
251
252     Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
253                        RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len);
254
255       }
256
257       break;
258
259  case RFCNB_SESSION_REQUEST:
260
261       fprintf(fd, "SESSION REQUEST: Length = %i\n",
262                   RFCNB_Pkt_Len(pkt -> data));
263       RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Called_Offset), lname);
264       fprintf(fd, "  Called Name: %s\n", lname);
265       RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Calling_Offset), lname);
266       fprintf(fd, "  Calling Name: %s\n", lname);
267
268       break;
269
270  case RFCNB_SESSION_ACK:
271
272       fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
273                   RFCNB_Pkt_Len(pkt -> data));
274
275       break;
276
277  case RFCNB_SESSION_REJ:
278       fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n",
279                   RFCNB_Pkt_Len(pkt -> data));
280
281       if (RFCNB_Pkt_Len(pkt -> data) < 1) {
282         fprintf(fd, "   Protocol Error, short Reject packet!\n");
283       }
284       else {
285         fprintf(fd, "   Error = %x\n", CVAL(pkt -> data, RFCNB_Pkt_Error_Offset));
286       }
287
288       break;
289
290  case RFCNB_SESSION_RETARGET:
291
292       fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
293                   RFCNB_Pkt_Len(pkt -> data));
294
295       /* Print out the IP address etc and the port? */
296
297       break;
298
299  case RFCNB_SESSION_KEEP_ALIVE:
300
301       fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
302               RFCNB_Pkt_Len(pkt -> data));
303       break;
304
305     default:
306
307       break;
308   }
309
310 }
311
312 /* Resolve a name into an address */
313
314 int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
315
316 { int addr;         /* Assumes IP4, 32 bit network addresses */
317   struct hostent *hp;
318
319         /* Use inet_addr to try to convert the address */
320
321   if ((addr = ip_getaddr(host)) == INADDR_NONE) { /* Not in DNS */
322
323         /* Try NetBIOS name lookup, how the hell do we do that? */
324
325       RFCNB_errno = RFCNBE_BadName;   /* Is this right? */
326       RFCNB_saved_errno = errno;
327       return(RFCNBE_Bad);
328
329   }
330   else { /* We got an IP address */
331
332     memcpy((void *)Dest_IP, (void *)&addr, sizeof(struct in_addr));
333
334   }
335
336   return 0;
337
338 }
339
340 /* Disconnect the TCP connection to the server */
341
342 int RFCNB_Close(int socket)
343
344 {
345
346   close(socket);
347
348   /* If we want to do error recovery, here is where we put it */
349
350   return 0;
351
352 }
353
354 /* Connect to the server specified in the IP address.
355    Not sure how to handle socket options etc.         */
356
357 int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
358
359 { struct sockaddr_in Socket;
360   int fd;
361
362   /* Create a socket */
363
364   if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
365
366     RFCNB_errno = RFCNBE_BadSocket;
367     RFCNB_saved_errno = errno;
368     return(RFCNBE_Bad);
369     }
370
371   bzero((char *)&Socket, sizeof(Socket));
372   memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
373
374   Socket.sin_port = htons(port);
375   Socket.sin_family = PF_INET;
376
377   /* Now connect to the destination */
378
379   if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) { /* Error */
380
381     close(fd);
382     RFCNB_errno = RFCNBE_ConnectFailed;
383     RFCNB_saved_errno = errno;
384     return(RFCNBE_Bad);
385     }
386
387   return(fd);
388
389 }
390
391 /* handle the details of establishing the RFCNB session with remote
392    end
393
394 */
395
396 int RFCNB_Session_Req(struct RFCNB_Con *con,
397                       char *Called_Name,
398                       char *Calling_Name,
399                       BOOL *redirect,
400                       struct in_addr *Dest_IP,
401                       int * port)
402
403 { char *sess_pkt;
404
405   /* Response packet should be no more than 9 bytes, make 16 jic */
406
407   char ln1[16], ln2[16], n1[32], n2[32], resp[16];
408   int len;
409   struct RFCNB_Pkt *pkt, res_pkt;
410
411   /* We build and send the session request, then read the response */
412
413   pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
414
415   if (pkt == NULL) {
416
417     return(RFCNBE_Bad);  /* Leave the error that RFCNB_Alloc_Pkt gives) */
418
419   }
420
421   sess_pkt = pkt -> data;    /* Get pointer to packet proper */
422
423   sess_pkt[RFCNB_Pkt_Type_Offset]  = RFCNB_SESSION_REQUEST;
424   RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
425   sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
426   sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
427
428   RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
429   RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
430
431   /* Now send the packet */
432
433 #ifdef RFCNB_DEBUG
434
435   fprintf(stderr, "Sending packet: ");
436
437 #endif
438
439   if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
440
441     return(RFCNBE_Bad);       /* Should be able to write that lot ... */
442
443     }
444
445 #ifdef RFCNB_DEBUG
446
447   fprintf(stderr, "Getting packet.\n");
448
449 #endif
450
451   res_pkt.data = resp;
452   res_pkt.len  = sizeof(resp);
453   res_pkt.next = NULL;
454
455   if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
456
457     return(RFCNBE_Bad);
458
459   }
460
461   /* Now analyze the packet ... */
462
463   switch (RFCNB_Pkt_Type(resp)) {
464
465     case RFCNB_SESSION_REJ:         /* Didnt like us ... too bad */
466
467       /* Why did we get rejected ? */
468
469       switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
470
471       case 0x80:
472         RFCNB_errno = RFCNBE_CallRejNLOCN;
473         break;
474       case 0x81:
475         RFCNB_errno = RFCNBE_CallRejNLFCN;
476         break;
477       case 0x82:
478         RFCNB_errno = RFCNBE_CallRejCNNP;
479         break;
480       case 0x83:
481         RFCNB_errno = RFCNBE_CallRejInfRes;
482         break;
483       case 0x8F:
484         RFCNB_errno = RFCNBE_CallRejUnSpec;
485         break;
486       default:
487         RFCNB_errno = RFCNBE_ProtErr;
488         break;
489       }
490
491       return(RFCNBE_Bad);
492       break;
493
494     case RFCNB_SESSION_ACK:        /* Got what we wanted ...      */
495
496       return(0);
497       break;
498
499     case RFCNB_SESSION_RETARGET:   /* Go elsewhere                */
500
501       *redirect = TRUE;       /* Copy port and ip addr       */
502
503       memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
504       *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
505
506       return(0);
507       break;
508
509     default:  /* A protocol error */
510
511       RFCNB_errno = RFCNBE_ProtErr;
512       return(RFCNBE_Bad);
513       break;
514     }
515 }
516
517
518
519
520
521
522
523
524