/src/samba/source4/libcli/smb_composite/connect_nego.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | |
4 | | Copyright (C) Stefan Metzmacher 2018 |
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 "libcli/composite/composite.h" |
23 | | #include "libcli/raw/libcliraw.h" |
24 | | #include "libcli/raw/raw_proto.h" |
25 | | #include "libcli/smb_composite/smb_composite.h" |
26 | | #include "lib/socket/socket.h" |
27 | | #include "libcli/resolve/resolve.h" |
28 | | #include "librpc/gen_ndr/ndr_nbt.h" |
29 | | #include "libcli/smb/smbXcli_base.h" |
30 | | |
31 | | struct smb_connect_nego_state { |
32 | | struct tevent_context *ev; |
33 | | struct resolve_context *resolve_ctx; |
34 | | const char *socket_options; |
35 | | struct smbcli_options options; |
36 | | const char *dest_hostname; |
37 | | const char *dest_address; |
38 | | const char *target_hostname; |
39 | | struct nbt_name calling, called; |
40 | | struct smbXcli_conn *conn; |
41 | | }; |
42 | | |
43 | | static void smb_connect_nego_connect_done(struct composite_context *creq); |
44 | | static void smb_connect_nego_nego_done(struct tevent_req *subreq); |
45 | | |
46 | | struct tevent_req *smb_connect_nego_send(TALLOC_CTX *mem_ctx, |
47 | | struct tevent_context *ev, |
48 | | struct loadparm_context *lp_ctx, |
49 | | struct resolve_context *resolve_ctx, |
50 | | const struct smbcli_options *options, |
51 | | const char *socket_options, |
52 | | const char *dest_hostname, |
53 | | const char *dest_address, /* optional */ |
54 | | const char *target_hostname, |
55 | | const char *called_name, |
56 | | const char *calling_name) |
57 | 0 | { |
58 | 0 | struct tevent_req *req = NULL; |
59 | 0 | struct smb_connect_nego_state *state = NULL; |
60 | 0 | struct composite_context *creq = NULL; |
61 | |
|
62 | 0 | req = tevent_req_create(mem_ctx, &state, |
63 | 0 | struct smb_connect_nego_state); |
64 | 0 | if (req == NULL) { |
65 | 0 | return NULL; |
66 | 0 | } |
67 | 0 | state->ev = ev; |
68 | 0 | state->resolve_ctx= resolve_ctx; |
69 | 0 | state->options = *options; |
70 | 0 | state->socket_options = socket_options; |
71 | 0 | state->dest_hostname = dest_hostname; |
72 | 0 | state->dest_address = dest_address; |
73 | 0 | state->target_hostname = target_hostname; |
74 | |
|
75 | 0 | make_nbt_name_client(&state->calling, calling_name); |
76 | |
|
77 | 0 | nbt_choose_called_name(state, &state->called, |
78 | 0 | called_name, NBT_NAME_SERVER); |
79 | 0 | if (tevent_req_nomem(state->called.name, req)) { |
80 | 0 | return tevent_req_post(req, ev); |
81 | 0 | } |
82 | | |
83 | 0 | creq = smbcli_sock_connect_send(state, |
84 | 0 | state->dest_address, |
85 | 0 | &state->options, |
86 | 0 | state->dest_hostname, |
87 | 0 | lp_ctx, |
88 | 0 | state->resolve_ctx, |
89 | 0 | state->ev, |
90 | 0 | state->socket_options, |
91 | 0 | &state->calling, |
92 | 0 | &state->called); |
93 | 0 | if (tevent_req_nomem(creq, req)) { |
94 | 0 | return tevent_req_post(req, ev); |
95 | 0 | } |
96 | 0 | creq->async.private_data = req; |
97 | 0 | creq->async.fn = smb_connect_nego_connect_done; |
98 | |
|
99 | 0 | return req; |
100 | 0 | } |
101 | | |
102 | | static void smb_connect_nego_connect_done(struct composite_context *creq) |
103 | 0 | { |
104 | 0 | struct tevent_req *req = |
105 | 0 | talloc_get_type_abort(creq->async.private_data, |
106 | 0 | struct tevent_req); |
107 | 0 | struct smb_connect_nego_state *state = |
108 | 0 | tevent_req_data(req, |
109 | 0 | struct smb_connect_nego_state); |
110 | 0 | struct tevent_req *subreq = NULL; |
111 | 0 | struct smbcli_socket *sock = NULL; |
112 | 0 | uint32_t smb1_capabilities; |
113 | 0 | uint32_t timeout_msec = state->options.request_timeout * 1000; |
114 | 0 | NTSTATUS status; |
115 | |
|
116 | 0 | status = smbcli_sock_connect_recv(creq, state, &sock); |
117 | 0 | creq = NULL; |
118 | 0 | if (tevent_req_nterror(req, status)) { |
119 | 0 | return; |
120 | 0 | } |
121 | | |
122 | 0 | smb1_capabilities = 0; |
123 | 0 | smb1_capabilities |= CAP_LARGE_FILES; |
124 | 0 | smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS; |
125 | 0 | smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND; |
126 | 0 | smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS; |
127 | 0 | smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX; |
128 | 0 | smb1_capabilities |= CAP_LWIO; |
129 | |
|
130 | 0 | if (state->options.ntstatus_support) { |
131 | 0 | smb1_capabilities |= CAP_STATUS32; |
132 | 0 | } |
133 | |
|
134 | 0 | if (state->options.unicode) { |
135 | 0 | smb1_capabilities |= CAP_UNICODE; |
136 | 0 | } |
137 | |
|
138 | 0 | if (state->options.use_spnego) { |
139 | 0 | smb1_capabilities |= CAP_EXTENDED_SECURITY; |
140 | 0 | } |
141 | |
|
142 | 0 | if (state->options.use_level2_oplocks) { |
143 | 0 | smb1_capabilities |= CAP_LEVEL_II_OPLOCKS; |
144 | 0 | } |
145 | |
|
146 | 0 | state->conn = smbXcli_conn_create(state, |
147 | 0 | &sock->transport, |
148 | 0 | state->target_hostname, |
149 | 0 | state->options.signing, |
150 | 0 | smb1_capabilities, |
151 | 0 | &state->options.client_guid, |
152 | 0 | state->options.smb2_capabilities, |
153 | 0 | &state->options.smb3_capabilities); |
154 | 0 | TALLOC_FREE(sock); |
155 | 0 | if (tevent_req_nomem(state->conn, req)) { |
156 | 0 | return; |
157 | 0 | } |
158 | | |
159 | 0 | subreq = smbXcli_negprot_send(state, |
160 | 0 | state->ev, |
161 | 0 | state->conn, |
162 | 0 | timeout_msec, |
163 | 0 | state->options.min_protocol, |
164 | 0 | state->options.max_protocol, |
165 | 0 | state->options.max_credits, |
166 | 0 | NULL); |
167 | 0 | if (tevent_req_nomem(subreq, req)) { |
168 | 0 | return; |
169 | 0 | } |
170 | 0 | tevent_req_set_callback(subreq, smb_connect_nego_nego_done, req); |
171 | 0 | } |
172 | | |
173 | | static void smb_connect_nego_nego_done(struct tevent_req *subreq) |
174 | 0 | { |
175 | 0 | struct tevent_req *req = |
176 | 0 | tevent_req_callback_data(subreq, |
177 | 0 | struct tevent_req); |
178 | 0 | NTSTATUS status; |
179 | |
|
180 | 0 | status = smbXcli_negprot_recv(subreq, NULL, NULL); |
181 | 0 | TALLOC_FREE(subreq); |
182 | 0 | if (tevent_req_nterror(req, status)) { |
183 | 0 | return; |
184 | 0 | } |
185 | | |
186 | 0 | tevent_req_done(req); |
187 | 0 | } |
188 | | |
189 | | NTSTATUS smb_connect_nego_recv(struct tevent_req *req, |
190 | | TALLOC_CTX *mem_ctx, |
191 | | struct smbXcli_conn **_conn) |
192 | 0 | { |
193 | 0 | struct smb_connect_nego_state *state = |
194 | 0 | tevent_req_data(req, |
195 | 0 | struct smb_connect_nego_state); |
196 | 0 | NTSTATUS status; |
197 | |
|
198 | 0 | if (tevent_req_is_nterror(req, &status)) { |
199 | 0 | tevent_req_received(req); |
200 | 0 | return status; |
201 | 0 | } |
202 | | |
203 | 0 | *_conn = talloc_move(mem_ctx, &state->conn); |
204 | 0 | tevent_req_received(req); |
205 | 0 | return NT_STATUS_OK; |
206 | 0 | } |