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