1 /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
4 RFCNB Utility Routines ...
6 Copyright (C) Richard Sharpe 1996
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.
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.
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.
28 #include <freeradius-devel/autoconf.h>
29 #include <freeradius-devel/libradius.h>
30 #include "std-includes.h"
31 #include "rfcnb-priv.h"
32 #include "rfcnb-util.h"
35 extern void (*Prot_Print_Routine)(); /* Pointer to protocol print routine */
37 /* Convert name and pad to 16 chars as needed */
38 /* Name 1 is a C string with null termination, name 2 may not be */
39 /* If SysName is true, then put a <00> on end, else space> */
41 void RFCNB_CvtPad_Name(char *name1, char *name2)
48 for (i = 0; i < 16; i++) {
52 c1 = 'C'; c2 = 'A'; /* CA is a space */
57 c1 = (char)((int)c/16 + (int)'A');
58 c2 = (char)((int)c%16 + (int)'A');
66 name2[32] = 0; /* Put in the nll ...*/
70 /* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
71 Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
72 to produce the next byte in the name.
74 This routine assumes that AName is 16 bytes long and that NBName has
75 space for 32 chars, so be careful ...
79 void RFCNB_AName_To_NBName(char *AName, char *NBName)
84 for (i=0; i < 16; i++) {
88 c1 = (char)((c >> 4) + 'A');
89 c2 = (char)((c & 0xF) + 'A');
95 NBName[32] = 0; /* Put in a null */
99 /* Do the reverse of the above ... */
101 void RFCNB_NBName_To_AName(char *NBName, char *AName)
106 for (i=0; i < 16; i++) {
111 c = (char)(((int)c1 - (int)'A') * 16 + ((int)c2 - (int)'A'));
117 AName[i] = 0; /* Put a null on the end ... */
121 /* Print a string of bytes in HEX etc */
123 void RFCNB_Print_Hex(FILE *fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
125 { char c1, c2, outbuf1[33];
128 struct RFCNB_Pkt *pkt_ptr = pkt;
129 static char Hex_List[17] = "0123456789ABCDEF";
133 /* We only want to print as much as sepcified in Len */
135 while (pkt_ptr != NULL) {
138 i < ((Len > (pkt_ptr -> len)?pkt_ptr -> len:Len) - Offset);
141 c = pkt_ptr -> data[i + Offset];
142 c1 = Hex_List[c >> 4];
143 c2 = Hex_List[c & 0xF];
145 outbuf1[j++] = c1; outbuf1[j++] = c2;
147 if (j == 32){ /* Print and reset */
149 fprintf(fd, " %s\n", outbuf1);
156 Len = Len - pkt_ptr -> len; /* Reduce amount by this much */
157 pkt_ptr = pkt_ptr -> next;
161 /* Print last lot in the buffer ... */
166 fprintf(fd, " %s\n", outbuf1);
174 /* Get a packet of size n */
176 struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
180 if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
182 RFCNB_errno = RFCNBE_NoSpace;
183 RFCNB_saved_errno = errno;
191 if (n == 0) return(pkt);
193 if ((pkt -> data = (char *)malloc(n)) == NULL) {
195 RFCNB_errno = RFCNBE_NoSpace;
196 RFCNB_saved_errno = errno;
206 /* Free up a packet */
208 int RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
210 { struct RFCNB_Pkt *pkt_next; char *data_ptr;
212 while (pkt != NULL) {
214 pkt_next = pkt -> next;
216 data_ptr = pkt -> data;
218 if (data_ptr != NULL)
229 /* Print an RFCNB packet */
231 void RFCNB_Print_Pkt(FILE *fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
235 /* We assume that the first fragment is the RFCNB Header */
236 /* We should loop through the fragments printing them out */
238 fprintf(fd, "RFCNB Pkt %s:", dirn);
240 switch (RFCNB_Pkt_Type(pkt -> data)) {
242 case RFCNB_SESSION_MESSAGE:
244 fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt -> data));
245 RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len,
246 #ifdef RFCNB_PRINT_DATA
247 RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len
252 if (Prot_Print_Routine != 0) { /* Print the rest of the packet */
254 Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
255 RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len);
261 case RFCNB_SESSION_REQUEST:
263 fprintf(fd, "SESSION REQUEST: Length = %i\n",
264 RFCNB_Pkt_Len(pkt -> data));
265 RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Called_Offset), lname);
266 fprintf(fd, " Called Name: %s\n", lname);
267 RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Calling_Offset), lname);
268 fprintf(fd, " Calling Name: %s\n", lname);
272 case RFCNB_SESSION_ACK:
274 fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
275 RFCNB_Pkt_Len(pkt -> data));
279 case RFCNB_SESSION_REJ:
280 fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n",
281 RFCNB_Pkt_Len(pkt -> data));
283 if (RFCNB_Pkt_Len(pkt -> data) < 1) {
284 fprintf(fd, " Protocol Error, short Reject packet!\n");
287 fprintf(fd, " Error = %x\n", CVAL(pkt -> data, RFCNB_Pkt_Error_Offset));
292 case RFCNB_SESSION_RETARGET:
294 fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
295 RFCNB_Pkt_Len(pkt -> data));
297 /* Print out the IP address etc and the port? */
301 case RFCNB_SESSION_KEEP_ALIVE:
303 fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
304 RFCNB_Pkt_Len(pkt -> data));
314 /* Resolve a name into an address */
316 int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
319 lrad_ipaddr_t ipaddr;
321 if (ip_hton(host, AF_INET, &ipaddr) < 0) {
322 /* Try NetBIOS name lookup, how the hell do we do that? */
324 RFCNB_errno = RFCNBE_BadName; /* Is this right? */
325 RFCNB_saved_errno = errno;
330 memcpy(Dest_IP, &ipaddr.ipaddr.ip4addr, sizeof(struct in_addr));
334 /* Disconnect the TCP connection to the server */
336 int RFCNB_Close(int socket)
342 /* If we want to do error recovery, here is where we put it */
348 /* Connect to the server specified in the IP address.
349 Not sure how to handle socket options etc. */
351 int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
353 { struct sockaddr_in Socket;
356 /* Create a socket */
358 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
360 RFCNB_errno = RFCNBE_BadSocket;
361 RFCNB_saved_errno = errno;
365 bzero((char *)&Socket, sizeof(Socket));
366 memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
368 Socket.sin_port = htons(port);
369 Socket.sin_family = PF_INET;
371 /* Now connect to the destination */
373 if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) { /* Error */
376 RFCNB_errno = RFCNBE_ConnectFailed;
377 RFCNB_saved_errno = errno;
385 /* handle the details of establishing the RFCNB session with remote
390 int RFCNB_Session_Req(struct RFCNB_Con *con,
394 struct in_addr *Dest_IP,
399 /* Response packet should be no more than 9 bytes, make 16 jic */
403 struct RFCNB_Pkt *pkt, res_pkt;
405 /* We build and send the session request, then read the response */
407 pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
411 return(RFCNBE_Bad); /* Leave the error that RFCNB_Alloc_Pkt gives) */
415 sess_pkt = pkt -> data; /* Get pointer to packet proper */
417 sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
418 RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
419 sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
420 sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
422 RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
423 RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
425 /* Now send the packet */
429 fprintf(stderr, "Sending packet: ");
433 if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
435 return(RFCNBE_Bad); /* Should be able to write that lot ... */
441 fprintf(stderr, "Getting packet.\n");
446 res_pkt.len = sizeof(resp);
449 if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
455 /* Now analyze the packet ... */
457 switch (RFCNB_Pkt_Type(resp)) {
459 case RFCNB_SESSION_REJ: /* Didnt like us ... too bad */
461 /* Why did we get rejected ? */
463 switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
466 RFCNB_errno = RFCNBE_CallRejNLOCN;
469 RFCNB_errno = RFCNBE_CallRejNLFCN;
472 RFCNB_errno = RFCNBE_CallRejCNNP;
475 RFCNB_errno = RFCNBE_CallRejInfRes;
478 RFCNB_errno = RFCNBE_CallRejUnSpec;
481 RFCNB_errno = RFCNBE_ProtErr;
488 case RFCNB_SESSION_ACK: /* Got what we wanted ... */
493 case RFCNB_SESSION_RETARGET: /* Go elsewhere */
495 *redirect = TRUE; /* Copy port and ip addr */
497 memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
498 *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
503 default: /* A protocol error */
505 RFCNB_errno = RFCNBE_ProtErr;