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