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