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