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