]>
Commit | Line | Data |
---|---|---|
462566c5 | 1 | /* |
ef57eb7b | 2 | * Copyright (C) 1996-2016 The Squid Software Foundation and contributors |
462566c5 AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
7c16470c AJ |
8 | |
9 | /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation | |
6ca34f6f HN |
10 | * |
11 | * Version 1.0 | |
12 | * Session Routines ... | |
13 | * | |
14 | * Copyright (C) Richard Sharpe 1996 | |
6ca34f6f | 15 | */ |
7c16470c AJ |
16 | |
17 | /* | |
6ca34f6f HN |
18 | * This program is free software; you can redistribute it and/or modify |
19 | * it under the terms of the GNU General Public License as published by | |
20 | * the Free Software Foundation; either version 2 of the License, or | |
21 | * (at your option) any later version. | |
22 | * | |
23 | * This program is distributed in the hope that it will be useful, | |
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
26 | * GNU General Public License for more details. | |
27 | * | |
28 | * You should have received a copy of the GNU General Public License | |
29 | * along with this program; if not, write to the Free Software | |
30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
31 | */ | |
7c16470c | 32 | |
462566c5 AJ |
33 | #include "squid.h" |
34 | ||
7c16470c AJ |
35 | int RFCNB_errno = 0; |
36 | int RFCNB_saved_errno = 0; | |
37 | #define RFCNB_ERRNO | |
38 | ||
39 | #include "rfcnb/std-includes.h" | |
40 | #include <netinet/tcp.h> | |
7c16470c | 41 | #include "rfcnb/rfcnb-io.h" |
9864722f | 42 | #include "rfcnb/rfcnb-priv.h" |
7c16470c | 43 | #include "rfcnb/rfcnb-util.h" |
9864722f | 44 | #include "rfcnb/rfcnb.h" |
7c16470c AJ |
45 | |
46 | #if HAVE_STRING_H | |
47 | #include <string.h> | |
48 | #endif | |
49 | ||
50 | int RFCNB_Stats[RFCNB_MAX_STATS]; | |
51 | ||
6ca34f6f | 52 | RFCNB_Prot_Print_Routine *Prot_Print_Routine = NULL; /* Pointer to protocol print routine */ |
7c16470c | 53 | |
7c16470c | 54 | /* Set up a session with a remote name. We are passed Called_Name as a |
6ca34f6f HN |
55 | * string which we convert to a NetBIOS name, ie space terminated, up to |
56 | * 16 characters only if we need to. If Called_Address is not empty, then | |
57 | * we use it to connect to the remote end, but put in Called_Name ... Called | |
58 | * Address can be a DNS based name, or a TCP/IP address ... | |
59 | */ | |
60 | ||
61 | void * | |
62 | RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address, int port) | |
7c16470c AJ |
63 | { |
64 | struct RFCNB_Con *con; | |
65 | struct in_addr Dest_IP; | |
66 | int Client; | |
67 | BOOL redirect; | |
68 | struct redirect_addr *redir_addr; | |
69 | char *Service_Address; | |
70 | ||
71 | /* Now, we really should look up the port in /etc/services ... */ | |
72 | ||
6ca34f6f HN |
73 | if (port == 0) |
74 | port = RFCNB_Default_Port; | |
7c16470c AJ |
75 | |
76 | /* Create a connection structure first */ | |
77 | ||
6ca34f6f | 78 | if ((con = (struct RFCNB_Con *) malloc(sizeof(struct RFCNB_Con))) == NULL) { /* Error in size */ |
7c16470c AJ |
79 | |
80 | RFCNB_errno = RFCNBE_NoSpace; | |
81 | RFCNB_saved_errno = errno; | |
6ca34f6f | 82 | return (NULL); |
7c16470c AJ |
83 | |
84 | } | |
6ca34f6f HN |
85 | con->fd = -0; /* no descriptor yet */ |
86 | con->errn = 0; /* no error yet */ | |
87 | con->timeout = 0; /* no timeout */ | |
88 | con->redirects = 0; | |
cdf6c008 | 89 | con->redirect_list = con->last_addr = NULL; |
7c16470c AJ |
90 | |
91 | /* Resolve that name into an IP address */ | |
92 | ||
93 | Service_Address = Called_Name; | |
b9bb9562 | 94 | if (strlen(Called_Address) != 0) { /* If the Called Address = "" */ |
7c16470c AJ |
95 | Service_Address = Called_Address; |
96 | } | |
6ca34f6f | 97 | if ((errno = RFCNB_Name_To_IP(Service_Address, &Dest_IP)) < 0) { /* Error */ |
7c16470c AJ |
98 | |
99 | /* No need to modify RFCNB_errno as it was done by RFCNB_Name_To_IP */ | |
100 | free(con); | |
6ca34f6f | 101 | return (NULL); |
7c16470c AJ |
102 | |
103 | } | |
7c16470c AJ |
104 | /* Now connect to the remote end */ |
105 | ||
6ca34f6f | 106 | redirect = TRUE; /* Fudge this one so we go once through */ |
7c16470c | 107 | |
6ca34f6f | 108 | while (redirect) { /* Connect and get session info etc */ |
7c16470c | 109 | |
6ca34f6f | 110 | redirect = FALSE; /* Assume all OK */ |
7c16470c AJ |
111 | |
112 | /* Build the redirect info. First one is first addr called */ | |
113 | /* And tack it onto the list of addresses we called */ | |
114 | ||
6ca34f6f | 115 | if ((redir_addr = (struct redirect_addr *) malloc(sizeof(struct redirect_addr))) == NULL) { /* Could not get space */ |
7c16470c AJ |
116 | |
117 | RFCNB_errno = RFCNBE_NoSpace; | |
118 | RFCNB_saved_errno = errno; | |
119 | free(con); | |
6ca34f6f | 120 | return (NULL); |
7c16470c AJ |
121 | |
122 | } | |
6ca34f6f HN |
123 | memcpy((char *) &(redir_addr->ip_addr), (char *) &Dest_IP, sizeof(Dest_IP)); |
124 | redir_addr->port = port; | |
125 | redir_addr->next = NULL; | |
7c16470c | 126 | |
6ca34f6f | 127 | if (con->redirect_list == NULL) { /* Stick on head */ |
7c16470c | 128 | |
6ca34f6f | 129 | con->redirect_list = con->last_addr = redir_addr; |
7c16470c AJ |
130 | |
131 | } else { | |
132 | ||
6ca34f6f HN |
133 | con->last_addr->next = redir_addr; |
134 | con->last_addr = redir_addr; | |
7c16470c AJ |
135 | |
136 | } | |
137 | ||
138 | /* Now, make that connection */ | |
139 | ||
6ca34f6f | 140 | if ((Client = RFCNB_IP_Connect(Dest_IP, port)) < 0) { /* Error */ |
7c16470c AJ |
141 | |
142 | /* No need to modify RFCNB_errno as it was done by RFCNB_IP_Connect */ | |
143 | free(con); | |
6ca34f6f | 144 | return (NULL); |
7c16470c AJ |
145 | |
146 | } | |
6ca34f6f | 147 | con->fd = Client; |
7c16470c AJ |
148 | |
149 | /* Now send and handle the RFCNB session request */ | |
150 | /* If we get a redirect, we will comeback with redirect true | |
6ca34f6f | 151 | * and a new IP address in DEST_IP */ |
7c16470c AJ |
152 | |
153 | if ((errno = RFCNB_Session_Req(con, | |
154 | Called_Name, | |
155 | Calling_Name, | |
156 | &redirect, &Dest_IP, &port)) < 0) { | |
157 | ||
158 | /* No need to modify RFCNB_errno as it was done by RFCNB_Session.. */ | |
159 | ||
6ca34f6f | 160 | RFCNB_Close(con->fd); /* Close it */ |
7c16470c | 161 | free(con); |
6ca34f6f | 162 | return (NULL); |
7c16470c AJ |
163 | |
164 | } | |
7c16470c AJ |
165 | if (redirect) { |
166 | ||
167 | /* We have to close the connection, and then try again */ | |
168 | ||
6ca34f6f | 169 | (con->redirects)++; |
7c16470c | 170 | |
6ca34f6f | 171 | RFCNB_Close(con->fd); /* Close it */ |
7c16470c AJ |
172 | |
173 | } | |
174 | } | |
175 | ||
6ca34f6f | 176 | return (con); |
7c16470c AJ |
177 | } |
178 | ||
179 | /* We send a packet to the other end ... for the moment, we treat the | |
6ca34f6f HN |
180 | * data as a series of pointers to blocks of data ... we should check the |
181 | * length ... */ | |
182 | int | |
183 | RFCNB_Send(struct RFCNB_Con *Con_Handle, struct RFCNB_Pkt *udata, int Length) | |
7c16470c AJ |
184 | { |
185 | struct RFCNB_Pkt *pkt; | |
186 | char *hdr; | |
187 | int len; | |
188 | ||
189 | /* Plug in the header and send the data */ | |
190 | ||
191 | pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len); | |
192 | ||
193 | if (pkt == NULL) { | |
194 | ||
195 | RFCNB_errno = RFCNBE_NoSpace; | |
196 | RFCNB_saved_errno = errno; | |
6ca34f6f | 197 | return (RFCNBE_Bad); |
7c16470c AJ |
198 | |
199 | } | |
6ca34f6f | 200 | pkt->next = udata; /* The user data we want to send */ |
7c16470c | 201 | |
6ca34f6f | 202 | hdr = pkt->data; |
7c16470c AJ |
203 | |
204 | /* Following crap is for portability across multiple UNIX machines */ | |
205 | ||
6ca34f6f | 206 | *(hdr + RFCNB_Pkt_Type_Offset) = RFCNB_SESSION_MESSAGE; |
7c16470c AJ |
207 | RFCNB_Put_Pkt_Len(hdr, Length); |
208 | ||
209 | #ifdef RFCNB_DEBUG | |
210 | ||
211 | fprintf(stderr, "Sending packet: "); | |
212 | ||
213 | #endif | |
214 | ||
215 | if ((len = RFCNB_Put_Pkt(Con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) { | |
216 | ||
217 | /* No need to change RFCNB_errno as it was done by put_pkt ... */ | |
218 | ||
cdf6c008 | 219 | RFCNB_Free_Pkt(pkt); |
6ca34f6f | 220 | return (RFCNBE_Bad); /* Should be able to write that lot ... */ |
7c16470c AJ |
221 | |
222 | } | |
7c16470c AJ |
223 | /* Now we have sent that lot, let's get rid of the RFCNB Header and return */ |
224 | ||
6ca34f6f | 225 | pkt->next = NULL; |
7c16470c AJ |
226 | |
227 | RFCNB_Free_Pkt(pkt); | |
228 | ||
6ca34f6f | 229 | return (len); |
7c16470c AJ |
230 | } |
231 | ||
232 | /* We pick up a message from the internet ... We have to worry about | |
6ca34f6f HN |
233 | * non-message packets ... */ |
234 | int | |
235 | RFCNB_Recv(void *con_Handle, struct RFCNB_Pkt *Data, int Length) | |
7c16470c AJ |
236 | { |
237 | struct RFCNB_Pkt *pkt; | |
238 | // struct RFCNB_Hdr *hdr; | |
239 | int ret_len; | |
240 | ||
241 | if (con_Handle == NULL) { | |
242 | ||
243 | RFCNB_errno = RFCNBE_BadHandle; | |
244 | RFCNB_saved_errno = errno; | |
6ca34f6f | 245 | return (RFCNBE_Bad); |
7c16470c AJ |
246 | |
247 | } | |
7c16470c AJ |
248 | /* Now get a packet from below. We allocate a header first */ |
249 | ||
250 | /* Plug in the header and send the data */ | |
251 | ||
252 | pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len); | |
253 | ||
254 | if (pkt == NULL) { | |
255 | ||
256 | RFCNB_errno = RFCNBE_NoSpace; | |
257 | RFCNB_saved_errno = errno; | |
6ca34f6f | 258 | return (RFCNBE_Bad); |
7c16470c AJ |
259 | |
260 | } | |
6ca34f6f | 261 | pkt->next = Data; /* Plug in the data portion */ |
7c16470c AJ |
262 | |
263 | if ((ret_len = RFCNB_Get_Pkt(con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) { | |
264 | ||
265 | #ifdef RFCNB_DEBUG | |
266 | fprintf(stderr, "Bad packet return in RFCNB_Recv... \n"); | |
267 | #endif | |
cdf6c008 | 268 | RFCNB_Free_Pkt(pkt); |
6ca34f6f | 269 | return (RFCNBE_Bad); |
7c16470c AJ |
270 | |
271 | } | |
7c16470c AJ |
272 | /* We should check that we go a message and not a keep alive */ |
273 | ||
6ca34f6f | 274 | pkt->next = NULL; |
7c16470c AJ |
275 | |
276 | RFCNB_Free_Pkt(pkt); | |
277 | ||
6ca34f6f | 278 | return (ret_len); |
7c16470c AJ |
279 | } |
280 | ||
281 | /* We just disconnect from the other end, as there is nothing in the RFCNB */ | |
282 | /* protocol that specifies any exchange as far as I can see */ | |
6ca34f6f HN |
283 | int |
284 | RFCNB_Hangup(struct RFCNB_Con *con_Handle) | |
7c16470c AJ |
285 | { |
286 | ||
287 | if (con_Handle != NULL) { | |
6ca34f6f | 288 | RFCNB_Close(con_Handle->fd); /* Could this fail? */ |
7c16470c AJ |
289 | free(con_Handle); |
290 | } | |
7c16470c | 291 | return 0; |
7c16470c AJ |
292 | } |
293 | ||
294 | /* Set TCP_NODELAY on the socket */ | |
6ca34f6f HN |
295 | int |
296 | RFCNB_Set_Sock_NoDelay(struct RFCNB_Con *con_Handle, BOOL yn) | |
7c16470c AJ |
297 | { |
298 | ||
6ca34f6f HN |
299 | return (setsockopt(con_Handle->fd, IPPROTO_TCP, TCP_NODELAY, |
300 | (char *) &yn, sizeof(yn))); | |
7c16470c AJ |
301 | } |
302 | ||
303 | #if NOT_IMPLEMENTED | |
7c16470c AJ |
304 | /* Listen for a connection on a port???, when */ |
305 | /* the connection comes in, we return with the connection */ | |
6ca34f6f HN |
306 | void * |
307 | RFCNB_Listen() | |
7c16470c | 308 | { |
7c16470c | 309 | } |
6ca34f6f | 310 | |
7c16470c AJ |
311 | #endif |
312 | ||
313 | /* Pick up the last error response as a string, hmmm, this routine should */ | |
314 | /* have been different ... */ | |
6ca34f6f HN |
315 | void |
316 | RFCNB_Get_Error(char *buffer, int buf_len) | |
7c16470c AJ |
317 | { |
318 | ||
319 | if (RFCNB_saved_errno <= 0) { | |
6ca34f6f | 320 | snprintf(buffer, (buf_len - 1), "%s", RFCNB_Error_Strings[RFCNB_errno]); |
7c16470c | 321 | } else { |
6ca34f6f | 322 | snprintf(buffer, (buf_len - 1), "%s\n\terrno:%s", RFCNB_Error_Strings[RFCNB_errno], |
3c96dd46 | 323 | strerror(RFCNB_saved_errno)); |
7c16470c | 324 | } |
7c16470c AJ |
325 | } |
326 | ||
327 | /* Pick up the last error response and returns as a code */ | |
6ca34f6f HN |
328 | int |
329 | RFCNB_Get_Last_Error() | |
7c16470c | 330 | { |
6ca34f6f | 331 | return (RFCNB_errno); |
7c16470c | 332 | } |
f53969cc | 333 |