Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : dcerpc over SMB transport
5 :
6 : Copyright (C) Tim Potter 2003
7 : Copyright (C) Andrew Tridgell 2003
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/filesys.h"
25 : #include <tevent.h>
26 : #include "lib/tsocket/tsocket.h"
27 : #include "libcli/smb/smb_constants.h"
28 : #include "libcli/smb/smbXcli_base.h"
29 : #include "libcli/smb/tstream_smbXcli_np.h"
30 : #include "libcli/raw/libcliraw.h"
31 : #include "libcli/smb2/smb2.h"
32 : #include "librpc/rpc/dcerpc.h"
33 : #include "librpc/rpc/dcerpc_proto.h"
34 : #include "libcli/composite/composite.h"
35 :
36 : #undef strncasecmp
37 :
38 : /* transport private information used by SMB pipe transport */
39 : struct smb_private {
40 : DATA_BLOB session_key;
41 :
42 : /*
43 : * these are needed to open a secondary connection
44 : */
45 : struct smbXcli_conn *conn;
46 : struct smbXcli_session *session;
47 : struct smbXcli_tcon *tcon;
48 : uint32_t timeout_msec;
49 : };
50 :
51 : /*
52 : fetch the user session key
53 : */
54 3234 : static NTSTATUS smb_session_key(struct dcecli_connection *c, DATA_BLOB *session_key)
55 : {
56 3234 : struct smb_private *smb = talloc_get_type_abort(
57 : c->transport.private_data, struct smb_private);
58 :
59 3234 : if (smb == NULL) return NT_STATUS_CONNECTION_DISCONNECTED;
60 :
61 3234 : if (smb->session_key.length == 0) {
62 0 : return NT_STATUS_NO_USER_SESSION_KEY;
63 : }
64 :
65 3234 : *session_key = smb->session_key;
66 3234 : return NT_STATUS_OK;
67 : }
68 :
69 : struct dcerpc_pipe_open_smb_state {
70 : struct dcecli_connection *c;
71 : struct composite_context *ctx;
72 :
73 : const char *fname;
74 :
75 : struct smb_private *smb;
76 : };
77 :
78 : static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq);
79 :
80 8065 : struct composite_context *dcerpc_pipe_open_smb_send(struct dcecli_connection *c,
81 : struct smbXcli_conn *conn,
82 : struct smbXcli_session *session,
83 : struct smbXcli_tcon *tcon,
84 : uint32_t timeout_msec,
85 : const char *pipe_name)
86 : {
87 620 : struct composite_context *ctx;
88 620 : struct dcerpc_pipe_open_smb_state *state;
89 8065 : uint16_t pid = 0;
90 620 : struct tevent_req *subreq;
91 :
92 8065 : ctx = composite_create(c, c->event_ctx);
93 8065 : if (ctx == NULL) return NULL;
94 :
95 8065 : state = talloc(ctx, struct dcerpc_pipe_open_smb_state);
96 8065 : if (composite_nomem(state, ctx)) return ctx;
97 8065 : ctx->private_data = state;
98 :
99 8065 : state->c = c;
100 8065 : state->ctx = ctx;
101 :
102 8065 : if ((strncasecmp(pipe_name, "/pipe/", 6) == 0) ||
103 8061 : (strncasecmp(pipe_name, "\\pipe\\", 6) == 0)) {
104 7900 : pipe_name += 6;
105 : }
106 8065 : if ((strncasecmp(pipe_name, "/", 1) == 0) ||
107 8065 : (strncasecmp(pipe_name, "\\", 1) == 0)) {
108 107 : pipe_name += 1;
109 : }
110 8065 : state->fname = talloc_strdup(state, pipe_name);
111 8065 : if (composite_nomem(state->fname, ctx)) return ctx;
112 :
113 8065 : state->smb = talloc_zero(state, struct smb_private);
114 8065 : if (composite_nomem(state->smb, ctx)) return ctx;
115 :
116 8065 : state->smb->conn = conn;
117 8065 : state->smb->session = session;
118 8065 : state->smb->tcon = tcon;
119 8065 : state->smb->timeout_msec = timeout_msec;
120 :
121 8065 : state->c->server_name = strupper_talloc(state->c,
122 : smbXcli_conn_remote_name(conn));
123 8065 : if (composite_nomem(state->c->server_name, ctx)) return ctx;
124 :
125 8065 : ctx->status = smbXcli_session_application_key(session,
126 7445 : state->smb,
127 8065 : &state->smb->session_key);
128 8065 : if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_NO_USER_SESSION_KEY)) {
129 369 : state->smb->session_key = data_blob_null;
130 369 : ctx->status = NT_STATUS_OK;
131 : }
132 8065 : if (!composite_is_ok(ctx)) return ctx;
133 :
134 8065 : subreq = tstream_smbXcli_np_open_send(state, c->event_ctx,
135 : conn, session, tcon, pid,
136 : timeout_msec, state->fname);
137 8065 : if (composite_nomem(subreq, ctx)) return ctx;
138 8065 : tevent_req_set_callback(subreq, dcerpc_pipe_open_smb_done, state);
139 :
140 8065 : return ctx;
141 : }
142 :
143 8065 : static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq)
144 : {
145 620 : struct dcerpc_pipe_open_smb_state *state =
146 8065 : tevent_req_callback_data(subreq,
147 : struct dcerpc_pipe_open_smb_state);
148 8065 : struct composite_context *ctx = state->ctx;
149 8065 : struct dcecli_connection *c = state->c;
150 620 : uint16_t enc_cipher;
151 :
152 8065 : ctx->status = tstream_smbXcli_np_open_recv(subreq,
153 : state->smb,
154 : &state->c->transport.stream);
155 8065 : TALLOC_FREE(subreq);
156 8065 : if (!composite_is_ok(ctx)) return;
157 :
158 15752 : state->c->transport.write_queue =
159 7876 : tevent_queue_create(state->c, "dcerpc_smb write queue");
160 7876 : if (composite_nomem(state->c->transport.write_queue, ctx)) return;
161 :
162 : /*
163 : fill in the transport methods
164 : */
165 7876 : c->transport.transport = NCACN_NP;
166 7876 : c->transport.private_data = NULL;
167 :
168 : /*
169 : * Windows uses 4280 for ncacn_np,
170 : * so we also use it, this is what our
171 : * tstream_smbXcli_np code relies on.
172 : */
173 7876 : c->srv_max_xmit_frag = 4280;
174 7876 : c->srv_max_recv_frag = 4280;
175 :
176 : /* Over-ride the default session key with the SMB session key */
177 7876 : c->security_state.session_key = smb_session_key;
178 :
179 7876 : enc_cipher = smb2cli_session_get_encryption_cipher(state->smb->session);
180 7876 : switch (enc_cipher) {
181 5 : case SMB2_ENCRYPTION_AES128_CCM:
182 : case SMB2_ENCRYPTION_AES128_GCM:
183 5 : c->transport.encrypted = true;
184 5 : break;
185 7871 : default:
186 7871 : c->transport.encrypted = false;
187 : }
188 :
189 7876 : c->transport.private_data = talloc_move(c, &state->smb);
190 :
191 7876 : composite_done(ctx);
192 : }
193 :
194 8065 : NTSTATUS dcerpc_pipe_open_smb_recv(struct composite_context *c)
195 : {
196 8065 : NTSTATUS status = composite_wait(c);
197 8065 : talloc_free(c);
198 8065 : return status;
199 : }
200 :
201 193 : _PUBLIC_ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p,
202 : struct smbcli_tree *t,
203 : const char *pipe_name)
204 : {
205 0 : struct smbXcli_conn *conn;
206 0 : struct smbXcli_session *session;
207 0 : struct smbXcli_tcon *tcon;
208 0 : struct composite_context *ctx;
209 :
210 193 : conn = t->session->transport->conn;
211 193 : session = t->session->smbXcli;
212 193 : tcon = t->smbXcli;
213 193 : smb1cli_tcon_set_id(tcon, t->tid);
214 :
215 : /* if we don't have a binding on this pipe yet, then create one */
216 193 : if (p->binding == NULL) {
217 0 : struct dcerpc_binding *b;
218 0 : NTSTATUS status;
219 193 : const char *r = smbXcli_conn_remote_name(conn);
220 0 : char *str;
221 193 : SMB_ASSERT(r != NULL);
222 193 : str = talloc_asprintf(p, "ncacn_np:%s", r);
223 193 : if (str == NULL) {
224 0 : return NT_STATUS_NO_MEMORY;
225 : }
226 193 : status = dcerpc_parse_binding(p, str, &b);
227 193 : talloc_free(str);
228 193 : if (!NT_STATUS_IS_OK(status)) {
229 0 : return status;
230 : }
231 193 : p->binding = b;
232 : }
233 :
234 193 : ctx = dcerpc_pipe_open_smb_send(p->conn,
235 : conn, session, tcon,
236 : DCERPC_REQUEST_TIMEOUT * 1000,
237 : pipe_name);
238 193 : if (ctx == NULL) {
239 0 : return NT_STATUS_NO_MEMORY;
240 : }
241 :
242 193 : return dcerpc_pipe_open_smb_recv(ctx);
243 : }
244 :
245 20 : _PUBLIC_ NTSTATUS dcerpc_pipe_open_smb2(struct dcerpc_pipe *p,
246 : struct smb2_tree *t,
247 : const char *pipe_name)
248 : {
249 0 : struct smbXcli_conn *conn;
250 0 : struct smbXcli_session *session;
251 0 : struct smbXcli_tcon *tcon;
252 0 : struct composite_context *ctx;
253 :
254 20 : conn = t->session->transport->conn;
255 20 : session = t->session->smbXcli;
256 20 : tcon = t->smbXcli;
257 :
258 : /* if we don't have a binding on this pipe yet, then create one */
259 20 : if (p->binding == NULL) {
260 0 : struct dcerpc_binding *b;
261 0 : NTSTATUS status;
262 20 : const char *r = smbXcli_conn_remote_name(conn);
263 0 : char *str;
264 20 : SMB_ASSERT(r != NULL);
265 20 : str = talloc_asprintf(p, "ncacn_np:%s", r);
266 20 : if (str == NULL) {
267 0 : return NT_STATUS_NO_MEMORY;
268 : }
269 20 : status = dcerpc_parse_binding(p, str, &b);
270 20 : talloc_free(str);
271 20 : if (!NT_STATUS_IS_OK(status)) {
272 0 : return status;
273 : }
274 20 : p->binding = b;
275 : }
276 :
277 20 : ctx = dcerpc_pipe_open_smb_send(p->conn,
278 : conn, session, tcon,
279 : DCERPC_REQUEST_TIMEOUT * 1000,
280 : pipe_name);
281 20 : if (ctx == NULL) {
282 0 : return NT_STATUS_NO_MEMORY;
283 : }
284 :
285 20 : return dcerpc_pipe_open_smb_recv(ctx);
286 : }
287 :
288 1210 : struct composite_context *dcerpc_secondary_smb_send(struct dcecli_connection *c1,
289 : struct dcecli_connection *c2,
290 : const char *pipe_name)
291 : {
292 230 : struct smb_private *smb;
293 :
294 1210 : if (c1->transport.transport != NCACN_NP) return NULL;
295 :
296 1210 : smb = talloc_get_type(c1->transport.private_data, struct smb_private);
297 1210 : if (!smb) return NULL;
298 :
299 1210 : return dcerpc_pipe_open_smb_send(c2,
300 : smb->conn,
301 : smb->session,
302 : smb->tcon,
303 : smb->timeout_msec,
304 : pipe_name);
305 : }
306 :
307 1210 : NTSTATUS dcerpc_secondary_smb_recv(struct composite_context *c)
308 : {
309 1210 : return dcerpc_pipe_open_smb_recv(c);
310 : }
|