s3-libsmb: run minimal_includes.pl.
[ira/wip.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/util/tevent_ntstatus.h"
22 #include "async_smb.h"
23 #include "libsmb/nmblib.h"
24
25 struct nb_connect_state {
26         struct tevent_context *ev;
27         const struct sockaddr_storage *addr;
28         const char *called_name;
29         int sock;
30
31         struct nmb_name called;
32         struct nmb_name calling;
33 };
34
35 static int nb_connect_state_destructor(struct nb_connect_state *state);
36 static void nb_connect_connected(struct tevent_req *subreq);
37 static void nb_connect_done(struct tevent_req *subreq);
38
39 static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
40                                           struct tevent_context *ev,
41                                           const struct sockaddr_storage *addr,
42                                           const char *called_name,
43                                           int called_type,
44                                           const char *calling_name,
45                                           int calling_type)
46 {
47         struct tevent_req *req, *subreq;
48         struct nb_connect_state *state;
49
50         req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
51         if (req == NULL) {
52                 return NULL;
53         }
54         state->ev = ev;
55         state->called_name = called_name;
56         state->addr = addr;
57
58         state->sock = -1;
59         make_nmb_name(&state->called, called_name, called_type);
60         make_nmb_name(&state->calling, calling_name, calling_type);
61
62         talloc_set_destructor(state, nb_connect_state_destructor);
63
64         subreq = open_socket_out_send(state, ev, addr, 139, 5000);
65         if (tevent_req_nomem(subreq, req)) {
66                 return tevent_req_post(req, ev);
67         }
68         tevent_req_set_callback(subreq, nb_connect_connected, req);
69         return req;
70 }
71
72 static int nb_connect_state_destructor(struct nb_connect_state *state)
73 {
74         if (state->sock != -1) {
75                 close(state->sock);
76         }
77         return 0;
78 }
79
80 static void nb_connect_connected(struct tevent_req *subreq)
81 {
82         struct tevent_req *req = tevent_req_callback_data(
83                 subreq, struct tevent_req);
84         struct nb_connect_state *state = tevent_req_data(
85                 req, struct nb_connect_state);
86         NTSTATUS status;
87
88         status = open_socket_out_recv(subreq, &state->sock);
89         TALLOC_FREE(subreq);
90         if (!NT_STATUS_IS_OK(status)) {
91                 tevent_req_nterror(req, status);
92                 return;
93         }
94         subreq = cli_session_request_send(state, state->ev, state->sock,
95                                           &state->called, &state->calling);
96         if (tevent_req_nomem(subreq, req)) {
97                 return;
98         }
99         tevent_req_set_callback(subreq, nb_connect_done, req);
100 }
101
102 static void nb_connect_done(struct tevent_req *subreq)
103 {
104         struct tevent_req *req = tevent_req_callback_data(
105                 subreq, struct tevent_req);
106         struct nb_connect_state *state = tevent_req_data(
107                 req, struct nb_connect_state);
108         bool ret;
109         int err;
110         uint8_t resp;
111
112         ret = cli_session_request_recv(subreq, &err, &resp);
113         TALLOC_FREE(subreq);
114         if (!ret) {
115                 tevent_req_nterror(req, map_nt_error_from_unix(err));
116                 return;
117         }
118
119         /*
120          * RFC1002: 0x82 - POSITIVE SESSION RESPONSE
121          */
122
123         if (resp != 0x82) {
124                 /*
125                  * The server did not like our session request
126                  */
127                 close(state->sock);
128                 state->sock = -1;
129
130                 if (strequal(state->called_name, "*SMBSERVER")) {
131                         /*
132                          * Here we could try a name status request and
133                          * use the first 0x20 type name.
134                          */
135                         tevent_req_nterror(
136                                 req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
137                         return;
138                 }
139
140                 /*
141                  * We could be subtle and distinguish between
142                  * different failure modes, but what we do here
143                  * instead is just retry with *SMBSERVER type 0x20.
144                  */
145                 state->called_name = "*SMBSERVER";
146                 make_nmb_name(&state->called, state->called_name, 0x20);
147
148                 subreq = open_socket_out_send(state, state->ev, state->addr,
149                                               139, 5000);
150                 if (tevent_req_nomem(subreq, req)) {
151                         return;
152                 }
153                 tevent_req_set_callback(subreq, nb_connect_connected, req);
154                 return;
155         }
156
157         tevent_req_done(req);
158         return;
159
160 }
161
162 static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
163 {
164         struct nb_connect_state *state = tevent_req_data(
165                 req, struct nb_connect_state);
166         NTSTATUS status;
167
168         if (tevent_req_is_nterror(req, &status)) {
169                 return status;
170         }
171         *sock = state->sock;
172         state->sock = -1;
173         return NT_STATUS_OK;
174 }
175
176 struct smbsock_connect_state {
177         struct tevent_context *ev;
178         const struct sockaddr_storage *addr;
179         const char *called_name;
180         uint8_t called_type;
181         const char *calling_name;
182         uint8_t calling_type;
183         struct tevent_req *req_139;
184         struct tevent_req *req_445;
185         int sock;
186         uint16_t port;
187 };
188
189 static int smbsock_connect_state_destructor(
190         struct smbsock_connect_state *state);
191 static void smbsock_connect_connected(struct tevent_req *subreq);
192 static void smbsock_connect_do_139(struct tevent_req *subreq);
193
194 struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx,
195                                         struct tevent_context *ev,
196                                         const struct sockaddr_storage *addr,
197                                         uint16_t port,
198                                         const char *called_name,
199                                         int called_type,
200                                         const char *calling_name,
201                                         int calling_type)
202 {
203         struct tevent_req *req, *subreq;
204         struct smbsock_connect_state *state;
205
206         req = tevent_req_create(mem_ctx, &state, struct smbsock_connect_state);
207         if (req == NULL) {
208                 return NULL;
209         }
210         state->ev = ev;
211         state->addr = addr;
212         state->sock = -1;
213         state->called_name =
214                 (called_name != NULL) ? called_name : "*SMBSERVER";
215         state->called_type =
216                 (called_type != -1) ? called_type : 0x20;
217         state->calling_name =
218                 (calling_name != NULL) ? calling_name : global_myname();
219         state->calling_type =
220                 (calling_type != -1) ? calling_type : 0x00;
221
222         talloc_set_destructor(state, smbsock_connect_state_destructor);
223
224         if (port == 139) {
225                 subreq = tevent_wakeup_send(state, ev, timeval_set(0, 0));
226                 if (tevent_req_nomem(subreq, req)) {
227                         return tevent_req_post(req, ev);
228                 }
229                 tevent_req_set_callback(subreq, smbsock_connect_do_139, req);
230                 return req;
231         }
232         if (port != 0) {
233                 state->req_445 = open_socket_out_send(state, ev, addr, port,
234                                                       5000);
235                 if (tevent_req_nomem(state->req_445, req)) {
236                         return tevent_req_post(req, ev);
237                 }
238                 tevent_req_set_callback(
239                         state->req_445, smbsock_connect_connected, req);
240                 return req;
241         }
242
243         /*
244          * port==0, try both
245          */
246
247         state->req_445 = open_socket_out_send(state, ev, addr, 445, 5000);
248         if (tevent_req_nomem(state->req_445, req)) {
249                 return tevent_req_post(req, ev);
250         }
251         tevent_req_set_callback(state->req_445, smbsock_connect_connected,
252                                 req);
253
254         /*
255          * After 5 msecs, fire the 139 request
256          */
257         state->req_139 = tevent_wakeup_send(
258                 state, ev, timeval_current_ofs(0, 5000));
259         if (tevent_req_nomem(state->req_139, req)) {
260                 TALLOC_FREE(state->req_445);
261                 return tevent_req_post(req, ev);
262         }
263         tevent_req_set_callback(state->req_139, smbsock_connect_do_139,
264                                 req);
265         return req;
266 }
267
268 static int smbsock_connect_state_destructor(
269         struct smbsock_connect_state *state)
270 {
271         if (state->sock != -1) {
272                 close(state->sock);
273         }
274         return 0;
275 }
276
277 static void smbsock_connect_do_139(struct tevent_req *subreq)
278 {
279         struct tevent_req *req = tevent_req_callback_data(
280                 subreq, struct tevent_req);
281         struct smbsock_connect_state *state = tevent_req_data(
282                 req, struct smbsock_connect_state);
283         bool ret;
284
285         ret = tevent_wakeup_recv(subreq);
286         TALLOC_FREE(subreq);
287         if (!ret) {
288                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
289                 return;
290         }
291         state->req_139 = nb_connect_send(state, state->ev, state->addr,
292                                          state->called_name,
293                                          state->called_type,
294                                          state->calling_name,
295                                          state->calling_type);
296         if (tevent_req_nomem(state->req_139, req)) {
297                 return;
298         }
299         tevent_req_set_callback(state->req_139, smbsock_connect_connected,
300                                 req);
301 }
302
303 static void smbsock_connect_connected(struct tevent_req *subreq)
304 {
305         struct tevent_req *req = tevent_req_callback_data(
306                 subreq, struct tevent_req);
307         struct smbsock_connect_state *state = tevent_req_data(
308                 req, struct smbsock_connect_state);
309         struct tevent_req *unfinished_req;
310         NTSTATUS status;
311
312         if (subreq == state->req_445) {
313
314                 status = open_socket_out_recv(subreq, &state->sock);
315                 TALLOC_FREE(state->req_445);
316                 unfinished_req = state->req_139;
317                 state->port = 445;
318
319         } else if (subreq == state->req_139) {
320
321                 status = nb_connect_recv(subreq, &state->sock);
322                 TALLOC_FREE(state->req_139);
323                 unfinished_req = state->req_445;
324                 state->port = 139;
325
326         } else {
327                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
328                 return;
329         }
330
331         if (NT_STATUS_IS_OK(status)) {
332                 TALLOC_FREE(unfinished_req);
333                 state->req_139 = NULL;
334                 state->req_445 = NULL;
335                 tevent_req_done(req);
336                 return;
337         }
338         if (unfinished_req == NULL) {
339                 /*
340                  * Both requests failed
341                  */
342                 tevent_req_nterror(req, status);
343                 return;
344         }
345         /*
346          * Do nothing, wait for the second request to come here.
347          */
348 }
349
350 NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
351                               uint16_t *ret_port)
352 {
353         struct smbsock_connect_state *state = tevent_req_data(
354                 req, struct smbsock_connect_state);
355         NTSTATUS status;
356
357         if (tevent_req_is_nterror(req, &status)) {
358                 return status;
359         }
360         *sock = state->sock;
361         state->sock = -1;
362         if (ret_port != NULL) {
363                 *ret_port = state->port;
364         }
365         return NT_STATUS_OK;
366 }
367
368 NTSTATUS smbsock_connect(const struct sockaddr_storage *addr, uint16_t port,
369                          const char *called_name, int called_type,
370                          const char *calling_name, int calling_type,
371                          int *pfd, uint16_t *ret_port, int sec_timeout)
372 {
373         TALLOC_CTX *frame = talloc_stackframe();
374         struct event_context *ev;
375         struct tevent_req *req;
376         NTSTATUS status = NT_STATUS_NO_MEMORY;
377
378         ev = event_context_init(frame);
379         if (ev == NULL) {
380                 goto fail;
381         }
382         req = smbsock_connect_send(frame, ev, addr, port,
383                                    called_name, called_type,
384                                    calling_name, calling_type);
385         if (req == NULL) {
386                 goto fail;
387         }
388         if ((sec_timeout != 0) &&
389             !tevent_req_set_endtime(
390                     req, ev, timeval_current_ofs(sec_timeout, 0))) {
391                 goto fail;
392         }
393         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
394                 goto fail;
395         }
396         status = smbsock_connect_recv(req, pfd, ret_port);
397  fail:
398         TALLOC_FREE(frame);
399         return status;
400 }
401
402 struct smbsock_any_connect_state {
403         struct tevent_context *ev;
404         const struct sockaddr_storage *addrs;
405         const char **called_names;
406         int *called_types;
407         const char **calling_names;
408         int *calling_types;
409         size_t num_addrs;
410         uint16_t port;
411
412         struct tevent_req **requests;
413         size_t num_sent;
414         size_t num_received;
415
416         int fd;
417         uint16_t chosen_port;
418         size_t chosen_index;
419 };
420
421 static bool smbsock_any_connect_send_next(
422         struct tevent_req *req, struct smbsock_any_connect_state *state);
423 static void smbsock_any_connect_trynext(struct tevent_req *subreq);
424 static void smbsock_any_connect_connected(struct tevent_req *subreq);
425
426 struct tevent_req *smbsock_any_connect_send(TALLOC_CTX *mem_ctx,
427                                             struct tevent_context *ev,
428                                             const struct sockaddr_storage *addrs,
429                                             const char **called_names,
430                                             int *called_types,
431                                             const char **calling_names,
432                                             int *calling_types,
433                                             size_t num_addrs, uint16_t port)
434 {
435         struct tevent_req *req, *subreq;
436         struct smbsock_any_connect_state *state;
437
438         req = tevent_req_create(mem_ctx, &state,
439                                 struct smbsock_any_connect_state);
440         if (req == NULL) {
441                 return NULL;
442         }
443         state->ev = ev;
444         state->addrs = addrs;
445         state->num_addrs = num_addrs;
446         state->called_names = called_names;
447         state->called_types = called_types;
448         state->calling_names = calling_names;
449         state->calling_types = calling_types;
450         state->port = port;
451
452         if (num_addrs == 0) {
453                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
454                 return tevent_req_post(req, ev);
455         }
456
457         state->requests = talloc_zero_array(state, struct tevent_req *,
458                                             num_addrs);
459         if (tevent_req_nomem(state->requests, req)) {
460                 return tevent_req_post(req, ev);
461         }
462         if (!smbsock_any_connect_send_next(req, state)) {
463                 return tevent_req_post(req, ev);
464         }
465         if (state->num_sent >= state->num_addrs) {
466                 return req;
467         }
468         subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 10000));
469         if (tevent_req_nomem(subreq, req)) {
470                 return tevent_req_post(req, ev);
471         }
472         tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
473         return req;
474 }
475
476 static void smbsock_any_connect_trynext(struct tevent_req *subreq)
477 {
478         struct tevent_req *req = tevent_req_callback_data(
479                 subreq, struct tevent_req);
480         struct smbsock_any_connect_state *state = tevent_req_data(
481                 req, struct smbsock_any_connect_state);
482         bool ret;
483
484         ret = tevent_wakeup_recv(subreq);
485         TALLOC_FREE(subreq);
486         if (!ret) {
487                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
488                 return;
489         }
490         if (!smbsock_any_connect_send_next(req, state)) {
491                 return;
492         }
493         if (state->num_sent >= state->num_addrs) {
494                 return;
495         }
496         subreq = tevent_wakeup_send(state, state->ev,
497                                     tevent_timeval_set(0, 10000));
498         if (tevent_req_nomem(subreq, req)) {
499                 return;
500         }
501         tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
502 }
503
504 static bool smbsock_any_connect_send_next(
505         struct tevent_req *req, struct smbsock_any_connect_state *state)
506 {
507         struct tevent_req *subreq;
508
509         if (state->num_sent >= state->num_addrs) {
510                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
511                 return false;
512         }
513         subreq = smbsock_connect_send(
514                 state->requests, state->ev, &state->addrs[state->num_sent],
515                 state->port,
516                 (state->called_names != NULL)
517                 ? state->called_names[state->num_sent] : NULL,
518                 (state->called_types != NULL)
519                 ? state->called_types[state->num_sent] : -1,
520                 (state->calling_names != NULL)
521                 ? state->calling_names[state->num_sent] : NULL,
522                 (state->calling_types != NULL)
523                 ? state->calling_types[state->num_sent] : -1);
524         if (tevent_req_nomem(subreq, req)) {
525                 return false;
526         }
527         tevent_req_set_callback(subreq, smbsock_any_connect_connected, req);
528
529         state->requests[state->num_sent] = subreq;
530         state->num_sent += 1;
531
532         return true;
533 }
534
535 static void smbsock_any_connect_connected(struct tevent_req *subreq)
536 {
537         struct tevent_req *req = tevent_req_callback_data(
538                 subreq, struct tevent_req);
539         struct smbsock_any_connect_state *state = tevent_req_data(
540                 req, struct smbsock_any_connect_state);
541         NTSTATUS status;
542         int fd;
543         uint16_t chosen_port;
544         size_t i;
545         size_t chosen_index = 0;
546
547         for (i=0; i<state->num_sent; i++) {
548                 if (state->requests[i] == subreq) {
549                         chosen_index = i;
550                         break;
551                 }
552         }
553         if (i == state->num_sent) {
554                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
555                 return;
556         }
557
558         status = smbsock_connect_recv(subreq, &fd, &chosen_port);
559
560         TALLOC_FREE(subreq);
561         state->requests[chosen_index] = NULL;
562
563         if (NT_STATUS_IS_OK(status)) {
564                 /*
565                  * This will kill all the other requests
566                  */
567                 TALLOC_FREE(state->requests);
568                 state->fd = fd;
569                 state->chosen_port = chosen_port;
570                 state->chosen_index = chosen_index;
571                 tevent_req_done(req);
572                 return;
573         }
574
575         state->num_received += 1;
576         if (state->num_received <= state->num_addrs) {
577                 /*
578                  * More addrs pending, wait for the others
579                  */
580                 return;
581         }
582
583         /*
584          * This is the last response, none succeeded.
585          */
586         tevent_req_nterror(req, status);
587         return;
588 }
589
590 NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd,
591                                   size_t *chosen_index,
592                                   uint16_t *chosen_port)
593 {
594         struct smbsock_any_connect_state *state = tevent_req_data(
595                 req, struct smbsock_any_connect_state);
596         NTSTATUS status;
597
598         if (tevent_req_is_nterror(req, &status)) {
599                 return status;
600         }
601         *pfd = state->fd;
602         if (chosen_index != NULL) {
603                 *chosen_index = state->chosen_index;
604         }
605         if (chosen_port != NULL) {
606                 *chosen_port = state->chosen_port;
607         }
608         return NT_STATUS_OK;
609 }
610
611 NTSTATUS smbsock_any_connect(const struct sockaddr_storage *addrs,
612                              const char **called_names,
613                              int *called_types,
614                              const char **calling_names,
615                              int *calling_types,
616                              size_t num_addrs,
617                              uint16_t port,
618                              int sec_timeout,
619                              int *pfd, size_t *chosen_index,
620                              uint16_t *chosen_port)
621 {
622         TALLOC_CTX *frame = talloc_stackframe();
623         struct event_context *ev;
624         struct tevent_req *req;
625         NTSTATUS status = NT_STATUS_NO_MEMORY;
626
627         ev = event_context_init(frame);
628         if (ev == NULL) {
629                 goto fail;
630         }
631         req = smbsock_any_connect_send(frame, ev, addrs,
632                                        called_names, called_types,
633                                        calling_names, calling_types,
634                                        num_addrs, port);
635         if (req == NULL) {
636                 goto fail;
637         }
638         if ((sec_timeout != 0) &&
639             !tevent_req_set_endtime(
640                     req, ev, timeval_current_ofs(sec_timeout, 0))) {
641                 goto fail;
642         }
643         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
644                 goto fail;
645         }
646         status = smbsock_any_connect_recv(req, pfd, chosen_index, chosen_port);
647  fail:
648         TALLOC_FREE(frame);
649         return status;
650 }