update otp_hotp() to support 6,7,8,9 digit otp's
[freeradius.git] / src / modules / rlm_smb / session.c
1 /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
2
3    Version 1.0
4    Session 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 int RFCNB_errno = 0;
29 int RFCNB_saved_errno = 0;
30 #define RFCNB_ERRNO
31
32 #include "std-includes.h"
33
34 #ifdef HAVE_NETINET_TCP_H
35 #include <netinet/tcp.h>
36 #endif
37
38 #include "rfcnb-priv.h"
39 #include "rfcnb-util.h"
40
41 int RFCNB_Stats[RFCNB_MAX_STATS];
42
43 void (*Prot_Print_Routine)() = NULL;      /* Pointer to print routine */
44
45 /* Set up a session with a remote name. We are passed Called_Name as a
46    string which we convert to a NetBIOS name, ie space terminated, up to
47    16 characters only if we need to. If Called_Address is not empty, then
48    we use it to connect to the remote end, but put in Called_Name ... Called
49    Address can be a DNS based name, or a TCP/IP address ...
50 */
51
52 void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
53                  int port)
54
55 { struct RFCNB_Con *con;
56   struct in_addr Dest_IP;
57   int Client;
58   BOOL redirect; struct redirect_addr *redir_addr;
59   char *Service_Address;
60
61   /* Now, we really should look up the port in /etc/services ... */
62
63   if (port == 0) port = RFCNB_Default_Port;
64
65   /* Create a connection structure first */
66
67   if ((con = (struct RFCNB_Con *)malloc(sizeof(struct RFCNB_Con))) == NULL) { /* Error in size */
68
69     RFCNB_errno = RFCNBE_NoSpace;
70     RFCNB_saved_errno = errno;
71     return(NULL);
72
73     }
74
75   con -> fd = -0;             /* no descriptor yet */
76   con -> rfc_errno = 0;           /* no error yet */
77   con -> timeout = 0;         /* no timeout   */
78   con -> redirects = 0;
79   con -> redirect_list = NULL; /* Fix bug still in version 0.50 */
80
81   /* Resolve that name into an IP address */
82
83   Service_Address = Called_Name;
84   if (strcmp(Called_Address, "") != 0) { /* If the Called Address = "" */
85     Service_Address = Called_Address;
86   }
87
88   if ((errno = RFCNB_Name_To_IP(Service_Address, &Dest_IP)) < 0) { /* Error */
89
90     /* No need to modify RFCNB_errno as it was done by RFCNB_Name_To_IP */
91
92     return(NULL);
93
94     }
95
96   /* Now connect to the remote end */
97
98   redirect = TRUE;     /* Fudge this one so we go once through */
99
100   while (redirect) {   /* Connect and get session info etc */
101
102     redirect = FALSE;  /* Assume all OK */
103
104     /* Build the redirect info. First one is first addr called */
105     /* And tack it onto the list of addresses we called        */
106
107     if ((redir_addr = (struct redirect_addr *)malloc(sizeof(struct redirect_addr))) == NULL) { /* Could not get space */
108
109       RFCNB_errno = RFCNBE_NoSpace;
110       RFCNB_saved_errno = errno;
111       return(NULL);
112
113     }
114
115     memcpy((char *)&(redir_addr -> ip_addr), (char *)&Dest_IP, sizeof(Dest_IP));
116     redir_addr -> port = port;
117     redir_addr -> next = NULL;
118
119     if (con -> redirect_list == NULL) { /* Stick on head */
120
121       con -> redirect_list = con -> last_addr = redir_addr;
122
123     } else {
124
125       con -> last_addr -> next = redir_addr;
126       con -> last_addr = redir_addr;
127
128     }
129
130     /* Now, make that connection */
131
132     if ((Client = RFCNB_IP_Connect(Dest_IP, port)) < 0) { /* Error */
133
134       /* No need to modify RFCNB_errno as it was done by RFCNB_IP_Connect */
135
136       return(NULL);
137
138       }
139
140     con -> fd = Client;
141
142     /* Now send and handle the RFCNB session request              */
143     /* If we get a redirect, we will comeback with redirect true
144        and a new IP address in DEST_IP                            */
145
146     if ((errno = RFCNB_Session_Req(con,
147                                    Called_Name,
148                                    Calling_Name,
149                                    &redirect, &Dest_IP, &port)) < 0) {
150
151       /* No need to modify RFCNB_errno as it was done by RFCNB_Session.. */
152
153       return(NULL);
154
155       }
156
157     if (redirect) {
158
159       /* We have to close the connection, and then try again */
160
161       (con -> redirects)++;
162
163       RFCNB_Close(con -> fd);  /* Close it */
164
165       }
166     }
167
168   return(con);
169
170 }
171
172 /* We send a packet to the other end ... for the moment, we treat the
173    data as a series of pointers to blocks of data ... we should check the
174    length ... */
175
176 int RFCNB_Send(struct RFCNB_Con *Con_Handle, struct RFCNB_Pkt *udata, int Length)
177
178 { struct RFCNB_Pkt *pkt; char *hdr;
179   int len;
180
181   /* Plug in the header and send the data */
182
183   pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
184
185   if (pkt == NULL) {
186
187     RFCNB_errno = RFCNBE_NoSpace;
188     RFCNB_saved_errno = errno;
189     return(RFCNBE_Bad);
190
191   }
192
193   pkt -> next = udata;   /* The user data we want to send */
194
195   hdr = pkt -> data;
196
197   /* Following crap is for portability across multiple UNIX machines */
198
199   *(hdr + RFCNB_Pkt_Type_Offset)  = RFCNB_SESSION_MESSAGE;
200   RFCNB_Put_Pkt_Len(hdr, Length);
201
202 #ifdef RFCNB_DEBUG
203
204   fprintf(stderr, "Sending packet: ");
205
206 #endif
207
208   if ((len = RFCNB_Put_Pkt(Con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
209
210     /* No need to change RFCNB_errno as it was done by put_pkt ...     */
211
212     return(RFCNBE_Bad);   /* Should be able to write that lot ... */
213
214   }
215
216   /* Now we have sent that lot, let's get rid of the RFCNB Header and return */
217
218   pkt -> next = NULL;
219
220   RFCNB_Free_Pkt(pkt);
221
222   return(len);
223
224 }
225
226 /* We pick up a message from the internet ... We have to worry about
227    non-message packets ...                                           */
228
229 int RFCNB_Recv(void *con_Handle, struct RFCNB_Pkt *Data, int Length)
230
231 {
232   struct RFCNB_Pkt *pkt;
233   int ret_len;
234
235   if (con_Handle == NULL){
236
237     RFCNB_errno = RFCNBE_BadHandle;
238     RFCNB_saved_errno = errno;
239     return(RFCNBE_Bad);
240
241   }
242
243   /* Now get a packet from below. We allocate a header first */
244
245   /* Plug in the header and send the data */
246
247   pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
248
249   if (pkt == NULL) {
250
251     RFCNB_errno = RFCNBE_NoSpace;
252     RFCNB_saved_errno = errno;
253     return(RFCNBE_Bad);
254
255   }
256
257   pkt -> next = Data;  /* Plug in the data portion */
258
259   if ((ret_len = RFCNB_Get_Pkt(con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
260
261 #ifdef RFCNB_DEBUG
262     fprintf(stderr, "Bad packet return in RFCNB_Recv... \n");
263 #endif
264
265     return(RFCNBE_Bad);
266
267   }
268
269   /* We should check that we go a message and not a keep alive */
270
271   pkt -> next = NULL;
272
273   RFCNB_Free_Pkt(pkt);
274
275   return(ret_len);
276
277 }
278
279 /* We just disconnect from the other end, as there is nothing in the RFCNB */
280 /* protocol that specifies any exchange as far as I can see                */
281
282 int RFCNB_Hangup(struct RFCNB_Con *con_Handle)
283
284 {
285
286   if (con_Handle != NULL) {
287     RFCNB_Close(con_Handle -> fd);  /* Could this fail? */
288     free(con_Handle);
289   }
290
291   return 0;
292
293
294 }
295
296 /* Set TCP_NODELAY on the socket                                          */
297
298 int RFCNB_Set_Sock_NoDelay(struct RFCNB_Con *con_Handle, BOOL yn)
299
300 {
301
302   return(setsockopt(con_Handle -> fd, IPPROTO_TCP, TCP_NODELAY,
303                     (char *)&yn, sizeof(yn)));
304
305 }
306
307
308 /* Listen for a connection on a port???, when                             */
309 /* the connection comes in, we return with the connection                 */
310
311 void *RFCNB_Listen()
312
313 {
314
315 }
316
317 /* Pick up the last error response as a string, hmmm, this routine should */
318 /* have been different ...                                                */
319
320 void RFCNB_Get_Error(char *buffer, int buf_len)
321
322 {
323
324   if (RFCNB_saved_errno <= 0) {
325     sprintf(buffer, "%s", RFCNB_Error_Strings[RFCNB_errno]);
326   }
327   else {
328     sprintf(buffer, "%s\n\terrno:%s", RFCNB_Error_Strings[RFCNB_errno],
329             strerror(RFCNB_saved_errno));
330   }
331
332 }
333
334 /* Pick up the last error response and returns as a code                 */
335
336 int RFCNB_Get_Last_Error()
337
338 {
339
340   return(RFCNB_errno);
341
342 }
343
344 /* Pick up saved errno as well */
345
346 int RFCNB_Get_Last_Errno()
347
348 {
349
350   return(RFCNB_saved_errno);
351
352 }
353
354 /* Pick up the last error response and return in string ...             */
355
356 int RFCNB_Get_Error_Msg(int code, char *msg_buf, int len)
357
358 {
359
360   strncpy(msg_buf, RFCNB_Error_Strings[abs(code)], len);
361
362 }
363
364 /* Register a higher level protocol print routine */
365
366 void RFCNB_Register_Print_Routine(void (*fn)())
367
368 {
369
370   Prot_Print_Routine = fn;
371
372 }