c56045cefd8907b62bdc87f6d3e55af140951afb
[obnox/samba-ctdb.git] / source3 / libsmb / smbsock_connect.c
1 /*
2    Unix SMB/CIFS implementation.
3    Connect to 445 and 139/nbsesssetup
4    Copyright (C) Volker Lendecke 2010
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "../lib/async_req/async_sock.h"
22 #include "async_smb.h"
23
24 struct nb_connect_state {
25         struct tevent_context *ev;
26         int sock;
27         struct nmb_name called;
28         struct nmb_name calling;
29 };
30
31 static int nb_connect_state_destructor(struct nb_connect_state *state);
32 static void nb_connect_connected(struct tevent_req *subreq);
33 static void nb_connect_done(struct tevent_req *subreq);
34
35 static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
36                                           struct tevent_context *ev,
37                                           const struct sockaddr_storage *addr,
38                                           const char *called_name,
39                                           int called_type,
40                                           const char *calling_name,
41                                           int calling_type)
42 {
43         struct tevent_req *req, *subreq;
44         struct nb_connect_state *state;
45
46         req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
47         if (req == NULL) {
48                 return NULL;
49         }
50         state->ev = ev;
51         make_nmb_name(&state->called, called_name, called_type);
52         make_nmb_name(&state->calling, calling_name, calling_type);
53         state->sock = -1;
54
55         talloc_set_destructor(state, nb_connect_state_destructor);
56
57         subreq = open_socket_out_send(state, ev, addr, 139, 5000);
58         if (tevent_req_nomem(subreq, req)) {
59                 return tevent_req_post(req, ev);
60         }
61         tevent_req_set_callback(subreq, nb_connect_connected, req);
62         return req;
63 }
64
65 static int nb_connect_state_destructor(struct nb_connect_state *state)
66 {
67         if (state->sock != -1) {
68                 close(state->sock);
69         }
70         return 0;
71 }
72
73 static void nb_connect_connected(struct tevent_req *subreq)
74 {
75         struct tevent_req *req = tevent_req_callback_data(
76                 subreq, struct tevent_req);
77         struct nb_connect_state *state = tevent_req_data(
78                 req, struct nb_connect_state);
79         NTSTATUS status;
80
81         status = open_socket_out_recv(subreq, &state->sock);
82         TALLOC_FREE(subreq);
83         if (!NT_STATUS_IS_OK(status)) {
84                 tevent_req_nterror(req, status);
85                 return;
86         }
87         subreq = cli_session_request_send(state, state->ev, state->sock,
88                                           &state->called, &state->calling);
89         if (tevent_req_nomem(subreq, req)) {
90                 return;
91         }
92         tevent_req_set_callback(subreq, nb_connect_done, req);
93 }
94
95 static void nb_connect_done(struct tevent_req *subreq)
96 {
97         struct tevent_req *req = tevent_req_callback_data(
98                 subreq, struct tevent_req);
99         bool ret;
100         int err;
101         uint8_t resp;
102
103         ret = cli_session_request_recv(subreq, &err, &resp);
104         TALLOC_FREE(subreq);
105         if (!ret) {
106                 tevent_req_nterror(req, map_nt_error_from_unix(err));
107                 return;
108         }
109         if (resp != 0x82) {
110                 tevent_req_nterror(req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
111                 return;
112         }
113         tevent_req_done(req);
114 }
115
116 static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
117 {
118         struct nb_connect_state *state = tevent_req_data(
119                 req, struct nb_connect_state);
120         NTSTATUS status;
121
122         if (tevent_req_is_nterror(req, &status)) {
123                 return status;
124         }
125         *sock = state->sock;
126         state->sock = -1;
127         return NT_STATUS_OK;
128 }
129
130 struct smbsock_connect_state {
131         struct tevent_context *ev;
132         const struct sockaddr_storage *addr;
133         const char *called_name;
134         const char *calling_name;
135         struct tevent_req *req_139;
136         struct tevent_req *req_445;
137         int sock;
138         uint16_t port;
139 };
140
141 static int smbsock_connect_state_destructor(
142         struct smbsock_connect_state *state);
143 static void smbsock_connect_connected(struct tevent_req *subreq);
144 static void smbsock_connect_do_139(struct tevent_req *subreq);
145
146 struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx,
147                                         struct tevent_context *ev,
148                                         const struct sockaddr_storage *addr,
149                                         const char *called_name,
150                                         const char *calling_name)
151 {
152         struct tevent_req *req, *subreq;
153         struct smbsock_connect_state *state;
154
155         req = tevent_req_create(mem_ctx, &state, struct smbsock_connect_state);
156         if (req == NULL) {
157                 return NULL;
158         }
159         state->ev = ev;
160         state->addr = addr;
161         state->sock = -1;
162         state->called_name =
163                 (called_name != NULL) ? called_name : "*SMBSERVER";
164         state->calling_name =
165                 (calling_name != NULL) ? calling_name : global_myname();
166
167         talloc_set_destructor(state, smbsock_connect_state_destructor);
168
169         state->req_445 = open_socket_out_send(state, ev, addr, 445, 5000);
170         if (tevent_req_nomem(state->req_445, req)) {
171                 return tevent_req_post(req, ev);
172         }
173         tevent_req_set_callback(state->req_445, smbsock_connect_connected,
174                                 req);
175
176         /*
177          * After 5 msecs, fire the 139 request
178          */
179         subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 5000));
180         if (tevent_req_nomem(subreq, req)) {
181                 TALLOC_FREE(state->req_445);
182                 return tevent_req_post(req, ev);
183         }
184         tevent_req_set_callback(subreq, smbsock_connect_do_139, req);
185         return req;
186 }
187
188 static int smbsock_connect_state_destructor(
189         struct smbsock_connect_state *state)
190 {
191         if (state->sock != -1) {
192                 close(state->sock);
193         }
194         return 0;
195 }
196
197 static void smbsock_connect_do_139(struct tevent_req *subreq)
198 {
199         struct tevent_req *req = tevent_req_callback_data(
200                 subreq, struct tevent_req);
201         struct smbsock_connect_state *state = tevent_req_data(
202                 req, struct smbsock_connect_state);
203         bool ret;
204
205         ret = tevent_wakeup_recv(subreq);
206         TALLOC_FREE(subreq);
207         if (!ret) {
208                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
209                 return;
210         }
211         state->req_139 = nb_connect_send(state, state->ev, state->addr,
212                                          state->called_name, 0x20,
213                                          state->calling_name, 0x0);
214         if (tevent_req_nomem(state->req_139, req)) {
215                 return;
216         }
217         tevent_req_set_callback(state->req_139, smbsock_connect_connected,
218                                 req);
219 }
220
221 static void smbsock_connect_connected(struct tevent_req *subreq)
222 {
223         struct tevent_req *req = tevent_req_callback_data(
224                 subreq, struct tevent_req);
225         struct smbsock_connect_state *state = tevent_req_data(
226                 req, struct smbsock_connect_state);
227         struct tevent_req *unfinished_req;
228         NTSTATUS status;
229
230         if (subreq == state->req_445) {
231
232                 status = open_socket_out_recv(subreq, &state->sock);
233                 TALLOC_FREE(state->req_445);
234                 unfinished_req = state->req_139;
235                 state->port = 445;
236
237         } else if (subreq == state->req_139) {
238
239                 status = nb_connect_recv(subreq, &state->sock);
240                 TALLOC_FREE(state->req_139);
241                 unfinished_req = state->req_445;
242                 state->port = 139;
243
244         } else {
245                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
246                 return;
247         }
248
249         if (NT_STATUS_IS_OK(status)) {
250                 TALLOC_FREE(unfinished_req);
251                 state->req_139 = NULL;
252                 state->req_445 = NULL;
253                 tevent_req_done(req);
254                 return;
255         }
256         if (unfinished_req == NULL) {
257                 /*
258                  * Both requests failed
259                  */
260                 tevent_req_nterror(req, status);
261                 return;
262         }
263         /*
264          * Do nothing, wait for the second request to come here.
265          */
266 }
267
268 NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
269                           uint16_t *port)
270 {
271         struct smbsock_connect_state *state = tevent_req_data(
272                 req, struct smbsock_connect_state);
273         NTSTATUS status;
274
275         if (tevent_req_is_nterror(req, &status)) {
276                 return status;
277         }
278         *sock = state->sock;
279         state->sock = -1;
280         if (port != NULL) {
281                 *port = state->port;
282         }
283         return NT_STATUS_OK;
284 }
285
286 NTSTATUS smbsock_connect(const struct sockaddr_storage *addr,
287                          const char *called_name, const char *calling_name,
288                          int *pfd, uint16_t *port)
289 {
290         TALLOC_CTX *frame = talloc_stackframe();
291         struct event_context *ev;
292         struct tevent_req *req;
293         NTSTATUS status = NT_STATUS_NO_MEMORY;
294
295         ev = event_context_init(frame);
296         if (ev == NULL) {
297                 goto fail;
298         }
299         req = smbsock_connect_send(frame, ev, addr, called_name, calling_name);
300         if (req == NULL) {
301                 goto fail;
302         }
303         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
304                 goto fail;
305         }
306         status = smbsock_connect_recv(req, pfd, port);
307  fail:
308         TALLOC_FREE(frame);
309         return status;
310 }
311
312 struct smbsock_any_connect_state {
313         struct tevent_context *ev;
314         const struct sockaddr_storage *addrs;
315         const char **called_names;
316         size_t num_addrs;
317
318         struct tevent_req **requests;
319         size_t num_sent;
320         size_t num_received;
321
322         int fd;
323         uint16_t port;
324         size_t chosen_index;
325 };
326
327 static bool smbsock_any_connect_send_next(
328         struct tevent_req *req, struct smbsock_any_connect_state *state);
329 static void smbsock_any_connect_trynext(struct tevent_req *subreq);
330 static void smbsock_any_connect_connected(struct tevent_req *subreq);
331
332 struct tevent_req *smbsock_any_connect_send(TALLOC_CTX *mem_ctx,
333                                             struct tevent_context *ev,
334                                             const struct sockaddr_storage *addrs,
335                                             const char **called_names,
336                                             size_t num_addrs)
337 {
338         struct tevent_req *req, *subreq;
339         struct smbsock_any_connect_state *state;
340
341         req = tevent_req_create(mem_ctx, &state,
342                                 struct smbsock_any_connect_state);
343         if (req == NULL) {
344                 return NULL;
345         }
346         state->ev = ev;
347         state->addrs = addrs;
348         state->num_addrs = num_addrs;
349         state->called_names = called_names;
350
351         if (num_addrs == 0) {
352                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
353                 return tevent_req_post(req, ev);
354         }
355
356         state->requests = talloc_zero_array(state, struct tevent_req *,
357                                             num_addrs);
358         if (tevent_req_nomem(state->requests, req)) {
359                 return tevent_req_post(req, ev);
360         }
361         if (!smbsock_any_connect_send_next(req, state)) {
362                 return tevent_req_post(req, ev);
363         }
364         if (state->num_sent >= state->num_addrs) {
365                 return req;
366         }
367         subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 10000));
368         if (tevent_req_nomem(subreq, req)) {
369                 return tevent_req_post(req, ev);
370         }
371         tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
372         return req;
373 }
374
375 static void smbsock_any_connect_trynext(struct tevent_req *subreq)
376 {
377         struct tevent_req *req = tevent_req_callback_data(
378                 subreq, struct tevent_req);
379         struct smbsock_any_connect_state *state = tevent_req_data(
380                 req, struct smbsock_any_connect_state);
381         bool ret;
382
383         ret = tevent_wakeup_recv(subreq);
384         TALLOC_FREE(subreq);
385         if (!ret) {
386                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
387                 return;
388         }
389         if (!smbsock_any_connect_send_next(req, state)) {
390                 return;
391         }
392         if (state->num_sent >= state->num_addrs) {
393                 return;
394         }
395         subreq = tevent_wakeup_send(state, state->ev,
396                                     tevent_timeval_set(0, 10000));
397         if (tevent_req_nomem(subreq, req)) {
398                 return;
399         }
400         tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
401 }
402
403 static bool smbsock_any_connect_send_next(
404         struct tevent_req *req, struct smbsock_any_connect_state *state)
405 {
406         struct tevent_req *subreq;
407
408         if (state->num_sent >= state->num_addrs) {
409                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
410                 return false;
411         }
412         subreq = smbsock_connect_send(
413                 state->requests, state->ev, &state->addrs[state->num_sent],
414                 (state->called_names != NULL)
415                 ? state->called_names[state->num_sent] : NULL,
416                 NULL);
417         if (tevent_req_nomem(subreq, req)) {
418                 return false;
419         }
420         tevent_req_set_callback(subreq, smbsock_any_connect_connected, req);
421
422         state->requests[state->num_sent] = subreq;
423         state->num_sent += 1;
424
425         return true;
426 }
427
428 static void smbsock_any_connect_connected(struct tevent_req *subreq)
429 {
430         struct tevent_req *req = tevent_req_callback_data(
431                 subreq, struct tevent_req);
432         struct smbsock_any_connect_state *state = tevent_req_data(
433                 req, struct smbsock_any_connect_state);
434         NTSTATUS status;
435         int fd;
436         uint16_t port;
437         size_t i;
438         size_t chosen_index = 0;
439
440         for (i=0; i<state->num_sent; i++) {
441                 if (state->requests[i] == subreq) {
442                         chosen_index = i;
443                         break;
444                 }
445         }
446         if (i == state->num_sent) {
447                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
448                 return;
449         }
450
451         status = smbsock_connect_recv(subreq, &fd, &port);
452
453         TALLOC_FREE(subreq);
454         state->requests[chosen_index] = NULL;
455
456         if (NT_STATUS_IS_OK(status)) {
457                 /*
458                  * This will kill all the other requests
459                  */
460                 TALLOC_FREE(state->requests);
461                 state->fd = fd;
462                 state->port = port;
463                 state->chosen_index = chosen_index;
464                 tevent_req_done(req);
465                 return;
466         }
467
468         state->num_received += 1;
469         if (state->num_received <= state->num_addrs) {
470                 /*
471                  * More addrs pending, wait for the others
472                  */
473                 return;
474         }
475
476         /*
477          * This is the last response, none succeeded.
478          */
479         tevent_req_nterror(req, status);
480         return;
481 }
482
483 NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd,
484                                   size_t *chosen_index, uint16_t *port)
485 {
486         struct smbsock_any_connect_state *state = tevent_req_data(
487                 req, struct smbsock_any_connect_state);
488         NTSTATUS status;
489
490         if (tevent_req_is_nterror(req, &status)) {
491                 return status;
492         }
493         *pfd = state->fd;
494         if (chosen_index != NULL) {
495                 *chosen_index = state->chosen_index;
496         }
497         if (port != NULL) {
498                 *port = state->port;
499         }
500         return NT_STATUS_OK;
501 }
502
503 NTSTATUS smbsock_any_connect(const struct sockaddr_storage *addrs,
504                              const char **called_names, size_t num_addrs,
505                              int *pfd, size_t *chosen_index, uint16_t *port)
506 {
507         TALLOC_CTX *frame = talloc_stackframe();
508         struct event_context *ev;
509         struct tevent_req *req;
510         NTSTATUS status = NT_STATUS_NO_MEMORY;
511
512         ev = event_context_init(frame);
513         if (ev == NULL) {
514                 goto fail;
515         }
516         req = smbsock_any_connect_send(frame, ev, addrs, called_names,
517                                        num_addrs);
518         if (req == NULL) {
519                 goto fail;
520         }
521         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
522                 goto fail;
523         }
524         status = smbsock_any_connect_recv(req, pfd, chosen_index, port);
525  fail:
526         TALLOC_FREE(frame);
527         return status;
528 }