source: trunk/server/source3/libsmb/smbsock_connect.c@ 845

Last change on this file since 845 was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 16.9 KB
Line 
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 "client.h"
23#include "async_smb.h"
24#include "libsmb/nmblib.h"
25
26struct nb_connect_state {
27 struct tevent_context *ev;
28 const struct sockaddr_storage *addr;
29 const char *called_name;
30 int sock;
31
32 struct nmb_name called;
33 struct nmb_name calling;
34};
35
36static int nb_connect_state_destructor(struct nb_connect_state *state);
37static void nb_connect_connected(struct tevent_req *subreq);
38static void nb_connect_done(struct tevent_req *subreq);
39
40static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
41 struct tevent_context *ev,
42 const struct sockaddr_storage *addr,
43 const char *called_name,
44 int called_type,
45 const char *calling_name,
46 int calling_type)
47{
48 struct tevent_req *req, *subreq;
49 struct nb_connect_state *state;
50
51 req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
52 if (req == NULL) {
53 return NULL;
54 }
55 state->ev = ev;
56 state->called_name = called_name;
57 state->addr = addr;
58
59 state->sock = -1;
60 make_nmb_name(&state->called, called_name, called_type);
61 make_nmb_name(&state->calling, calling_name, calling_type);
62
63 talloc_set_destructor(state, nb_connect_state_destructor);
64
65 subreq = open_socket_out_send(state, ev, addr, 139, 5000);
66 if (tevent_req_nomem(subreq, req)) {
67 return tevent_req_post(req, ev);
68 }
69 tevent_req_set_callback(subreq, nb_connect_connected, req);
70 return req;
71}
72
73static int nb_connect_state_destructor(struct nb_connect_state *state)
74{
75 if (state->sock != -1) {
76 close(state->sock);
77 }
78 return 0;
79}
80
81static void nb_connect_connected(struct tevent_req *subreq)
82{
83 struct tevent_req *req = tevent_req_callback_data(
84 subreq, struct tevent_req);
85 struct nb_connect_state *state = tevent_req_data(
86 req, struct nb_connect_state);
87 NTSTATUS status;
88
89 status = open_socket_out_recv(subreq, &state->sock);
90 TALLOC_FREE(subreq);
91 if (!NT_STATUS_IS_OK(status)) {
92 tevent_req_nterror(req, status);
93 return;
94 }
95 subreq = cli_session_request_send(state, state->ev, state->sock,
96 &state->called, &state->calling);
97 if (tevent_req_nomem(subreq, req)) {
98 return;
99 }
100 tevent_req_set_callback(subreq, nb_connect_done, req);
101}
102
103static void nb_connect_done(struct tevent_req *subreq)
104{
105 struct tevent_req *req = tevent_req_callback_data(
106 subreq, struct tevent_req);
107 struct nb_connect_state *state = tevent_req_data(
108 req, struct nb_connect_state);
109 bool ret;
110 int err;
111 uint8_t resp;
112
113 ret = cli_session_request_recv(subreq, &err, &resp);
114 TALLOC_FREE(subreq);
115 if (!ret) {
116 tevent_req_nterror(req, map_nt_error_from_unix(err));
117 return;
118 }
119
120 /*
121 * RFC1002: 0x82 - POSITIVE SESSION RESPONSE
122 */
123
124 if (resp != 0x82) {
125 /*
126 * The server did not like our session request
127 */
128 close(state->sock);
129 state->sock = -1;
130
131 if (strequal(state->called_name, "*SMBSERVER")) {
132 /*
133 * Here we could try a name status request and
134 * use the first 0x20 type name.
135 */
136 tevent_req_nterror(
137 req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
138 return;
139 }
140
141 /*
142 * We could be subtle and distinguish between
143 * different failure modes, but what we do here
144 * instead is just retry with *SMBSERVER type 0x20.
145 */
146 state->called_name = "*SMBSERVER";
147 make_nmb_name(&state->called, state->called_name, 0x20);
148
149 subreq = open_socket_out_send(state, state->ev, state->addr,
150 139, 5000);
151 if (tevent_req_nomem(subreq, req)) {
152 return;
153 }
154 tevent_req_set_callback(subreq, nb_connect_connected, req);
155 return;
156 }
157
158 tevent_req_done(req);
159 return;
160
161}
162
163static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
164{
165 struct nb_connect_state *state = tevent_req_data(
166 req, struct nb_connect_state);
167 NTSTATUS status;
168
169 if (tevent_req_is_nterror(req, &status)) {
170 return status;
171 }
172 *sock = state->sock;
173 state->sock = -1;
174 return NT_STATUS_OK;
175}
176
177struct smbsock_connect_state {
178 struct tevent_context *ev;
179 const struct sockaddr_storage *addr;
180 const char *called_name;
181 uint8_t called_type;
182 const char *calling_name;