1 /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
4 RFCNB Utility Routines ...
6 Copyright (C) Richard Sharpe 1996
7 Copyright 2006 The FreeRADIUS server project
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.
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.
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.
27 #include <freeradius-devel/ident.h>
32 #include <freeradius-devel/autoconf.h>
33 #include <freeradius-devel/libradius.h>
34 #include "std-includes.h"
35 #include "rfcnb-priv.h"
36 #include "rfcnb-util.h"
39 extern void (*Prot_Print_Routine)(); /* Pointer to protocol print routine */
41 /* Convert name and pad to 16 chars as needed */
42 /* Name 1 is a C string with null termination, name 2 may not be */
43 /* If SysName is true, then put a <00> on end, else space> */
45 void RFCNB_CvtPad_Name(char *name1, char *name2)
52 for (i = 0; i < 16; i++) {
56 c1 = 'C'; c2 = 'A'; /* CA is a space */
61 c1 = (char)((int)c/16 + (int)'A');
62 c2 = (char)((int)c%16 + (int)'A');
70 name2[32] = 0; /* Put in the nll ...*/
74 /* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
75 Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
76 to produce the next byte in the name.
78 This routine assumes that AName is 16 bytes long and that NBName has
79 space for 32 chars, so be careful ...
83 void RFCNB_AName_To_NBName(char *AName, char *NBName)
88 for (i=0; i < 16; i++) {
92 c1 = (char)((c >> 4) + 'A');
93 c2 = (char)((c & 0xF) + 'A');
99 NBName[32] = 0; /* Put in a null */
103 /* Do the reverse of the above ... */
105 void RFCNB_NBName_To_AName(char *NBName, char *AName)
110 for (i=0; i < 16; i++) {
115 c = (char)(((int)c1 - (int)'A') * 16 + ((int)c2 - (int)'A'));
121 AName[i] = 0; /* Put a null on the end ... */
125 /* Print a string of bytes in HEX etc */
127 void RFCNB_Print_Hex(FILE *fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
129 { char c1, c2, outbuf1[33];
132 struct RFCNB_Pkt *pkt_ptr = pkt;
133 static char Hex_List[17] = "0123456789ABCDEF";
137 /* We only want to print as much as sepcified in Len */
139 while (pkt_ptr != NULL) {
142 i < ((Len > (pkt_ptr -> len)?pkt_ptr -> len:Len) - Offset);
145 c = pkt_ptr -> data[i + Offset];
146 c1 = Hex_List[c >> 4];
147 c2 = Hex_List[c & 0xF];
149 outbuf1[j++] = c1; outbuf1[j++] = c2;
151 if (j == 32){ /* Print and reset */
153 fprintf(fd, " %s\n", outbuf1);
160 Len = Len - pkt_ptr -> len; /* Reduce amount by this much */
161 pkt_ptr = pkt_ptr -> next;
165 /* Print last lot in the buffer ... */
170 fprintf(fd, " %s\n", outbuf1);
178 /* Get a packet of size n */
180 struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
184 if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
186 RFCNB_errno = RFCNBE_NoSpace;
187 RFCNB_saved_errno = errno;
195 if (n == 0) return(pkt);
197 if ((pkt -> data = (char *)malloc(n)) == NULL) {
199 RFCNB_errno = RFCNBE_NoSpace;
200 RFCNB_saved_errno = errno;
210 /* Free up a packet */
212 int RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
214 { struct RFCNB_Pkt *pkt_next; char *data_ptr;
216 while (pkt != NULL) {
218 pkt_next = pkt -> next;
220 data_ptr = pkt -> data;
222 if (data_ptr != NULL)
233 /* Print an RFCNB packet */
235 void RFCNB_Print_Pkt(FILE *fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
239 /* We assume that the first fragment is the RFCNB Header */
240 /* We should loop through the fragments printing them out */
242 fprintf(fd, "RFCNB Pkt %s:", dirn);
244 switch (RFCNB_Pkt_Type(pkt -> data)) {
246 case RFCNB_SESSION_MESSAGE:
248 fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt -> data));
249 RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len,
250 #ifdef RFCNB_PRINT_DATA
251 RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len
256 if (Prot_Print_Routine != 0) { /* Print the rest of the packet */
258 Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
259 RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len);
265 case RFCNB_SESSION_REQUEST:
267 fprintf(fd, "SESSION REQUEST: Length = %i\n",
268 RFCNB_Pkt_Len(pkt -> data));
269 RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Called_Offset), lname);
270 fprintf(fd, " Called Name: %s\n", lname);
271 RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Calling_Offset), lname);
272 fprintf(fd, " Calling Name: %s\n", lname);
276 case RFCNB_SESSION_ACK:
278 fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
279 RFCNB_Pkt_Len(pkt -> data));
283 case RFCNB_SESSION_REJ:
284 fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n",
285 RFCNB_Pkt_Len(pkt -> data));
287 if (RFCNB_Pkt_Len(pkt -> data) < 1) {
288 fprintf(fd, " Protocol Error, short Reject packet!\n");
291 fprintf(fd, " Error = %x\n", CVAL(pkt -> data, RFCNB_Pkt_Error_Offset));
296 case RFCNB_SESSION_RETARGET:
298 fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
299 RFCNB_Pkt_Len(pkt -> data));
301 /* Print out the IP address etc and the port? */
305 case RFCNB_SESSION_KEEP_ALIVE:
307 fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
308 RFCNB_Pkt_Len(pkt -> data));
318 /* Resolve a name into an address */
320 int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
323 lrad_ipaddr_t ipaddr;
325 if (ip_hton(host, AF_INET, &ipaddr) < 0) {
326 /* Try NetBIOS name lookup, how the hell do we do that? */
328 RFCNB_errno = RFCNBE_BadName; /* Is this right? */
329 RFCNB_saved_errno = errno;
334 memcpy(Dest_IP, &ipaddr.ipaddr.ip4addr, sizeof(struct in_addr));
338 /* Disconnect the TCP connection to the server */
340 int RFCNB_Close(int socket)
346 /* If we want to do error recovery, here is where we put it */
352 /* Connect to the server specified in the IP address.
353 Not sure how to handle socket options etc. */
355 int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
357 { struct sockaddr_in Socket;
360 /* Create a socket */
362 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
364 RFCNB_errno = RFCNBE_BadSocket;
365 RFCNB_saved_errno = errno;
369 bzero((char *)&Socket, sizeof(Socket));
370 memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
372 Socket.sin_port = htons(port);
373 Socket.sin_family = PF_INET;
375 /* Now connect to the destination */
377 if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) { /* Error */
380 RFCNB_errno = RFCNBE_ConnectFailed;
381 RFCNB_saved_errno = errno;
389 /* handle the details of establishing the RFCNB session with remote
394 int RFCNB_Session_Req(struct RFCNB_Con *con,
398 struct in_addr *Dest_IP,
403 /* Response packet should be no more than 9 bytes, make 16 jic */
407 struct RFCNB_Pkt *pkt, res_pkt;
409 /* We build and send the session request, then read the response */
411 pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
415 return(RFCNBE_Bad); /* Leave the error that RFCNB_Alloc_Pkt gives) */
419 sess_pkt = pkt -> data; /* Get pointer to packet proper */
421 sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
422 RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
423 sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
424 sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
426 RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
427 RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
429 /* Now send the packet */
433 fprintf(stderr, "Sending packet: ");
437 if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
439 return(RFCNBE_Bad); /* Should be able to write that lot ... */
445 fprintf(stderr, "Getting packet.\n");
450 res_pkt.len = sizeof(resp);
453 if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
459 /* Now analyze the packet ... */
461 switch (RFCNB_Pkt_Type(resp)) {
463 case RFCNB_SESSION_REJ: /* Didnt like us ... too bad */
465 /* Why did we get rejected ? */
467 switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
470 RFCNB_errno = RFCNBE_CallRejNLOCN;
473 RFCNB_errno = RFCNBE_CallRejNLFCN;
476 RFCNB_errno = RFCNBE_CallRejCNNP;
479 RFCNB_errno = RFCNBE_CallRejInfRes;
482 RFCNB_errno = RFCNBE_CallRejUnSpec;
485 RFCNB_errno = RFCNBE_ProtErr;
492 case RFCNB_SESSION_ACK: /* Got what we wanted ... */
497 case RFCNB_SESSION_RETARGET: /* Go elsewhere */
499 *redirect = TRUE; /* Copy port and ip addr */
501 memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
502 *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
507 default: /* A protocol error */
509 RFCNB_errno = RFCNBE_ProtErr;