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