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.
26
#include "std-includes.h"
27
#include "rfcnb-priv.h"
28
#include "rfcnb-util.h"
33
#include <sys/types.h>
34
#include <sys/socket.h>
35
#include <netinet/in.h>
36
#include <arpa/inet.h>
39
char *RFCNB_Error_Strings[] =
42
"RFCNBE_OK: Routine completed successfully.",
43
"RFCNBE_NoSpace: No space available for a malloc call.",
44
"RFCNBE_BadName: NetBIOS name could not be translated to IP address.",
45
"RFCNBE_BadRead: Read system call returned an error. Check errno.",
46
"RFCNBE_BadWrite: Write system call returned an error. Check errno.",
47
"RFCNBE_ProtErr: A protocol error has occurred.",
48
"RFCNBE_ConGone: Connection dropped during a read or write system call.",
49
"RFCNBE_BadHandle: Bad connection handle passed.",
50
"RFCNBE_BadSocket: Problems creating socket.",
51
"RFCNBE_ConnectFailed: Connection failed. See errno.",
52
"RFCNBE_CallRejNLOCN: Call rejected. Not listening on called name.",
53
"RFCNBE_CallRejNLFCN: Call rejected. Not listening for called name.",
54
"RFCNBE_CallRejCNNP: Call rejected. Called name not present.",
55
"RFCNBE_CallRejInfRes: Call rejected. Name present, but insufficient resources.",
56
"RFCNBE_CallRejUnSpec: Call rejected. Unspecified error.",
57
"RFCNBE_BadParam: Bad parameters passed to a routine.",
58
"RFCNBE_Timeout: IO Operation timed out ..."
62
extern void (*Prot_Print_Routine) (); /* Pointer to protocol print routine */
64
/* Convert name and pad to 16 chars as needed */
65
/* Name 1 is a C string with null termination, name 2 may not be */
66
/* If SysName is true, then put a <00> on end, else space> */
69
RFCNB_CvtPad_Name(char *name1, char *name2)
76
for (i = 0; i < 16; i++) {
81
c2 = 'A'; /* CA is a space */
86
c1 = (char) ((int) c / 16 + (int) 'A');
87
c2 = (char) ((int) c % 16 + (int) 'A');
91
name2[i * 2 + 1] = c2;
95
name2[32] = 0; /* Put in the nll ... */
99
/* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
100
* Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
101
* to produce the next byte in the name.
103
* This routine assumes that AName is 16 bytes long and that NBName has
104
* space for 32 chars, so be careful ...
109
RFCNB_AName_To_NBName(char *AName, char *NBName)
114
for (i = 0; i < 16; i++) {
118
c1 = (char) ((c >> 4) + 'A');
119
c2 = (char) ((c & 0xF) + 'A');
122
NBName[i * 2 + 1] = c2;
125
NBName[32] = 0; /* Put in a null */
129
/* Do the reverse of the above ... */
132
RFCNB_NBName_To_AName(char *NBName, char *AName)
137
for (i = 0; i < 16; i++) {
140
c2 = NBName[i * 2 + 1];
142
c = (char) (((int) c1 - (int) 'A') * 16 + ((int) c2 - (int) 'A'));
148
AName[i] = 0; /* Put a null on the end ... */
152
/* Print a string of bytes in HEX etc */
155
RFCNB_Print_Hex(FILE * fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
157
char c1, c2, outbuf1[33];
160
struct RFCNB_Pkt *pkt_ptr = pkt;
161
static char Hex_List[17] = "0123456789ABCDEF";
165
/* We only want to print as much as sepcified in Len */
167
while (pkt_ptr != NULL) {
170
i < ((Len > (pkt_ptr->len) ? pkt_ptr->len : Len) - Offset);
173
c = pkt_ptr->data[i + Offset];
174
c1 = Hex_List[c >> 4];
175
c2 = Hex_List[c & 0xF];
180
if (j == 32) { /* Print and reset */
182
fprintf(fd, " %s\n", outbuf1);
188
Len = Len - pkt_ptr->len; /* Reduce amount by this much */
189
pkt_ptr = pkt_ptr->next;
193
/* Print last lot in the buffer ... */
198
fprintf(fd, " %s\n", outbuf1);
205
/* Get a packet of size n */
208
RFCNB_Alloc_Pkt(int n)
212
if ((pkt = (struct RFCNB_Pkt *) malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
214
RFCNB_errno = RFCNBE_NoSpace;
215
RFCNB_saved_errno = errno;
225
if ((pkt->data = (char *) malloc(n)) == NULL) {
227
RFCNB_errno = RFCNBE_NoSpace;
228
RFCNB_saved_errno = errno;
237
/* Free up a packet */
240
RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
242
struct RFCNB_Pkt *pkt_next;
245
while (pkt != NULL) {
247
pkt_next = pkt->next;
249
data_ptr = pkt->data;
251
if (data_ptr != NULL)
262
/* Print an RFCNB packet */
265
RFCNB_Print_Pkt(FILE * fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
269
/* We assume that the first fragment is the RFCNB Header */
270
/* We should loop through the fragments printing them out */
272
fprintf(fd, "RFCNB Pkt %s:", dirn);
274
switch (RFCNB_Pkt_Type(pkt->data)) {
276
case RFCNB_SESSION_MESSAGE:
278
fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt->data));
279
RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len,
280
#ifdef RFCNB_PRINT_DATA
281
RFCNB_Pkt_Len(pkt->data) - RFCNB_Pkt_Hdr_Len);
286
if (Prot_Print_Routine != 0) { /* Print the rest of the packet */
288
Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
289
RFCNB_Pkt_Len(pkt->data) - RFCNB_Pkt_Hdr_Len);
294
case RFCNB_SESSION_REQUEST:
296
fprintf(fd, "SESSION REQUEST: Length = %i\n",
297
RFCNB_Pkt_Len(pkt->data));
298
RFCNB_NBName_To_AName((char *) (pkt->data + RFCNB_Pkt_Called_Offset), lname);
299
fprintf(fd, " Called Name: %s\n", lname);
300
RFCNB_NBName_To_AName((char *) (pkt->data + RFCNB_Pkt_Calling_Offset), lname);
301
fprintf(fd, " Calling Name: %s\n", lname);
305
case RFCNB_SESSION_ACK:
307
fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
308
RFCNB_Pkt_Len(pkt->data));
312
case RFCNB_SESSION_REJ:
313
fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n",
314
RFCNB_Pkt_Len(pkt->data));
316
if (RFCNB_Pkt_Len(pkt->data) < 1) {
317
fprintf(fd, " Protocol Error, short Reject packet!\n");
319
fprintf(fd, " Error = %x\n", CVAL(pkt->data, RFCNB_Pkt_Error_Offset));
324
case RFCNB_SESSION_RETARGET:
326
fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
327
RFCNB_Pkt_Len(pkt->data));
329
/* Print out the IP address etc and the port? */
333
case RFCNB_SESSION_KEEP_ALIVE:
335
fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
336
RFCNB_Pkt_Len(pkt->data));
346
/* Resolve a name into an address */
349
RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
351
int addr; /* Assumes IP4, 32 bit network addresses */
354
/* Use inet_addr to try to convert the address */
356
if ((addr = inet_addr(host)) == INADDR_NONE) { /* Oh well, a good try :-) */
358
/* Now try a name look up with gethostbyname */
360
if ((hp = gethostbyname(host)) == NULL) { /* Not in DNS */
362
/* Try NetBIOS name lookup, how the hell do we do that? */
364
RFCNB_errno = RFCNBE_BadName; /* Is this right? */
365
RFCNB_saved_errno = errno;
368
} else { /* We got a name */
370
memcpy((void *) Dest_IP, (void *) hp->h_addr_list[0], sizeof(struct in_addr));
373
} else { /* It was an IP address */
375
memcpy((void *) Dest_IP, (void *) &addr, sizeof(struct in_addr));
383
/* Disconnect the TCP connection to the server */
386
RFCNB_Close(int socket)
391
/* If we want to do error recovery, here is where we put it */
397
/* Connect to the server specified in the IP address.
398
* Not sure how to handle socket options etc. */
401
RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
403
struct sockaddr_in Socket;
406
/* Create a socket */
408
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
410
RFCNB_errno = RFCNBE_BadSocket;
411
RFCNB_saved_errno = errno;
414
bzero((char *) &Socket, sizeof(Socket));
415
memcpy((char *) &Socket.sin_addr, (char *) &Dest_IP, sizeof(Dest_IP));
417
Socket.sin_port = htons(port);
418
Socket.sin_family = PF_INET;
420
/* Now connect to the destination */
422
if (connect(fd, (struct sockaddr *) &Socket, sizeof(Socket)) < 0) { /* Error */
425
RFCNB_errno = RFCNBE_ConnectFailed;
426
RFCNB_saved_errno = errno;
433
/* handle the details of establishing the RFCNB session with remote
439
RFCNB_Session_Req(struct RFCNB_Con *con,
443
struct in_addr *Dest_IP,
448
/* Response packet should be no more than 9 bytes, make 16 jic */
452
struct RFCNB_Pkt *pkt, res_pkt;
454
/* We build and send the session request, then read the response */
456
pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
460
return (RFCNBE_Bad); /* Leave the error that RFCNB_Alloc_Pkt gives) */
463
sess_pkt = pkt->data; /* Get pointer to packet proper */
465
sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
466
RFCNB_Put_Pkt_Len(sess_pkt, (RFCNB_Pkt_Sess_Len - RFCNB_Pkt_Hdr_Len));
467
sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
468
sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
470
RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
471
RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
473
/* Now send the packet */
477
fprintf(stderr, "Sending packet: ");
481
if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
483
return (RFCNBE_Bad); /* Should be able to write that lot ... */
488
fprintf(stderr, "Getting packet.\n");
493
res_pkt.len = sizeof(resp);
496
if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
501
/* Now analyze the packet ... */
503
switch (RFCNB_Pkt_Type(resp)) {
505
case RFCNB_SESSION_REJ: /* Didnt like us ... too bad */
507
/* Why did we get rejected ? */
509
switch (CVAL(resp, RFCNB_Pkt_Error_Offset)) {
512
RFCNB_errno = RFCNBE_CallRejNLOCN;
515
RFCNB_errno = RFCNBE_CallRejNLFCN;
518
RFCNB_errno = RFCNBE_CallRejCNNP;
521
RFCNB_errno = RFCNBE_CallRejInfRes;
524
RFCNB_errno = RFCNBE_CallRejUnSpec;
527
RFCNB_errno = RFCNBE_ProtErr;
534
case RFCNB_SESSION_ACK: /* Got what we wanted ... */
539
case RFCNB_SESSION_RETARGET: /* Go elsewhere */
541
*redirect = TRUE; /* Copy port and ip addr */
543
memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
544
*port = SVAL(resp, RFCNB_Pkt_Port_Offset);
549
default: /* A protocol error */
551
RFCNB_errno = RFCNBE_ProtErr;