Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : [MS-RPCH] - RPC over HTTP client
5 :
6 : Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
7 : Copyright (C) Julien Kerihuel <j.kerihuel@openchange.org> 2013
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 <tevent.h>
25 : #include <talloc.h>
26 : #include "lib/tsocket/tsocket.h"
27 : #include "lib/tls/tls.h"
28 : #include "lib/util/tevent_ntstatus.h"
29 : #include "lib/util/util_net.h"
30 : #include "libcli/resolve/resolve.h"
31 : #include "libcli/composite/composite.h"
32 : #include "auth/credentials/credentials.h"
33 : #include "auth/credentials/credentials_internal.h"
34 : #include <gen_ndr/dcerpc.h>
35 : #include <gen_ndr/ndr_dcerpc.h>
36 :
37 : #include "librpc/rpc/dcerpc.h"
38 : #include "librpc/rpc/dcerpc_roh.h"
39 : #include "librpc/rpc/dcerpc_proto.h"
40 : #include "libcli/http/http.h"
41 :
42 : struct roh_request_state {
43 : struct http_request *request;
44 : struct http_request *response;
45 : };
46 :
47 : static void roh_send_RPC_DATA_IN_done(struct tevent_req *subreq);
48 0 : struct tevent_req *roh_send_RPC_DATA_IN_send(TALLOC_CTX *mem_ctx,
49 : struct loadparm_context *lp_ctx,
50 : struct tevent_context *ev,
51 : struct cli_credentials *credentials,
52 : struct roh_connection *roh,
53 : const char *rpc_server,
54 : uint32_t rpc_server_port,
55 : const char *rpc_proxy,
56 : uint8_t http_auth)
57 : {
58 0 : struct tevent_req *req;
59 0 : struct tevent_req *subreq;
60 0 : struct roh_request_state *state;
61 0 : const char *path;
62 0 : char *query;
63 0 : char *uri;
64 :
65 0 : DEBUG(8, ("%s: Sending RPC_IN_DATA request\n", __func__));
66 :
67 0 : req = tevent_req_create(mem_ctx, &state, struct roh_request_state);
68 0 : if (req == NULL) {
69 0 : return NULL;
70 : }
71 :
72 0 : state->request = talloc_zero(state, struct http_request);
73 0 : if (tevent_req_nomem(state->request, req)) {
74 0 : return tevent_req_post(req, ev);
75 : }
76 :
77 : /* Build URI, as specified in section 2.2.2 */
78 0 : query = talloc_asprintf(state, "%s:%d", rpc_server, rpc_server_port);
79 0 : if (tevent_req_nomem(query, req)) {
80 0 : return tevent_req_post(req, ev);
81 : }
82 :
83 : /*
84 : * TODO This path changes to "/rpcwithcert/rpcproxy.dll" when using
85 : * certificates
86 : */
87 0 : path = "/rpc/rpcproxy.dll";
88 0 : uri = talloc_asprintf(state, "%s?%s", path, query);
89 0 : if (tevent_req_nomem(uri, req)) {
90 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
91 0 : return tevent_req_post(req, ev);
92 : }
93 0 : TALLOC_FREE(query);
94 :
95 : /*
96 : * Create the HTTP channel IN request as specified in the
97 : * section 2.1.2.1.1
98 : */
99 0 : state->request->type = HTTP_REQ_RPC_IN_DATA;
100 0 : state->request->uri = uri;
101 0 : state->request->body.length = 0;
102 0 : state->request->body.data = NULL;
103 0 : state->request->major = '1';
104 0 : state->request->minor = '0';
105 :
106 0 : http_add_header(state, &state->request->headers,
107 : "Accept", "application/rpc");
108 0 : http_add_header(state, &state->request->headers,
109 : "User-Agent", "MSRPC");
110 0 : http_add_header(state, &state->request->headers,
111 : "Host", rpc_proxy);
112 0 : http_add_header(state, &state->request->headers,
113 : "Connection", "keep-alive");
114 0 : http_add_header(state, &state->request->headers,
115 : "Content-Length", "1073741824");
116 0 : http_add_header(state, &state->request->headers,
117 : "Cache-Control", "no-cache");
118 0 : http_add_header(state, &state->request->headers,
119 : "Pragma", "no-cache");
120 :
121 0 : subreq = http_send_auth_request_send(state,
122 : ev,
123 0 : roh->default_channel_in->http_conn,
124 0 : state->request,
125 : credentials,
126 : lp_ctx,
127 : http_auth);
128 0 : if (tevent_req_nomem(subreq, req)) {
129 0 : return tevent_req_post(req, ev);
130 : }
131 0 : tevent_req_set_callback(subreq, roh_send_RPC_DATA_IN_done, req);
132 :
133 0 : return req;
134 : }
135 :
136 0 : static void roh_send_RPC_DATA_IN_done(struct tevent_req *subreq)
137 : {
138 0 : NTSTATUS status;
139 0 : struct tevent_req *req;
140 :
141 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
142 :
143 : /* Receive the sent bytes to check if request has been properly sent */
144 0 : status = http_send_auth_request_recv(subreq);
145 0 : TALLOC_FREE(subreq);
146 0 : if (tevent_req_nterror(req, status)) {
147 0 : return;
148 : }
149 :
150 0 : DEBUG(8, ("%s: RPC_IN_DATA sent\n", __func__));
151 :
152 0 : tevent_req_done(req);
153 : }
154 :
155 0 : NTSTATUS roh_send_RPC_DATA_IN_recv(struct tevent_req *req)
156 : {
157 0 : NTSTATUS status;
158 :
159 0 : if (tevent_req_is_nterror(req, &status)) {
160 0 : tevent_req_received(req);
161 0 : return status;
162 : }
163 :
164 0 : tevent_req_received(req);
165 0 : return NT_STATUS_OK;
166 : }
167 :
168 : struct roh_send_pdu_state {
169 : DATA_BLOB buffer;
170 : struct iovec iov;
171 : int bytes_written;
172 : int sys_errno;
173 : };
174 :
175 : static void roh_send_CONN_B1_done(struct tevent_req *subreq);
176 0 : struct tevent_req *roh_send_CONN_B1_send(TALLOC_CTX *mem_ctx,
177 : struct tevent_context *ev,
178 : struct roh_connection *roh)
179 : {
180 0 : struct tevent_req *req;
181 0 : struct tevent_req *subreq;
182 0 : struct roh_send_pdu_state *state;
183 0 : struct dcerpc_rts rts;
184 0 : struct ncacn_packet pkt;
185 0 : struct ndr_push *ndr;
186 0 : struct tstream_context *stream = NULL;
187 0 : struct tevent_queue *send_queue = NULL;
188 :
189 0 : DEBUG(8, ("%s: Sending CONN/B1 request\n", __func__));
190 :
191 0 : req = tevent_req_create(mem_ctx, &state, struct roh_send_pdu_state);
192 0 : if (req == NULL) {
193 0 : return NULL;
194 : }
195 :
196 0 : rts.Flags = RTS_FLAG_NONE;
197 0 : rts.NumberOfCommands = 6;
198 0 : rts.Commands = talloc_array(state, struct dcerpc_rts_cmd, 6);
199 :
200 : /* CONN/B1: Version RTS command */
201 0 : rts.Commands[0].CommandType = 0x00000006;
202 0 : rts.Commands[0].Command.Version.Version = 0x00000001;
203 :
204 : /* CONN/B1: VirtualConnectionCookie RTS command */
205 0 : rts.Commands[1].CommandType = 0x00000003;
206 0 : rts.Commands[1].Command.Cookie.Cookie.Cookie = roh->connection_cookie;
207 :
208 : /* CONN/B1: InChannelCookie RTS command */
209 0 : rts.Commands[2].CommandType = 0x00000003;
210 0 : rts.Commands[2].Command.Cookie.Cookie.Cookie =
211 0 : roh->default_channel_in->channel_cookie;
212 :
213 : /* CONN/B1: ChannelLifetime */
214 0 : rts.Commands[3].CommandType = 0x00000004;
215 0 : rts.Commands[3].Command.ReceiveWindowSize.ReceiveWindowSize =
216 : 0x40000000;
217 :
218 : /* CONN/B1: ClientKeepAlive */
219 0 : rts.Commands[4].CommandType = 0x00000005;
220 0 : rts.Commands[4].Command.ClientKeepalive.ClientKeepalive = 0x000493e0;
221 :
222 : /* CONN/B1: AssociationGroupId */
223 0 : rts.Commands[5].CommandType = 0x0000000C;
224 0 : rts.Commands[5].Command.AssociationGroupId.AssociationGroupId.Cookie =
225 : roh->association_group_id_cookie;
226 :
227 0 : pkt.rpc_vers = 5;
228 0 : pkt.rpc_vers_minor = 0;
229 0 : pkt.ptype = DCERPC_PKT_RTS;
230 0 : pkt.pfc_flags = DCERPC_PFC_FLAG_LAST | DCERPC_PFC_FLAG_FIRST;
231 0 : pkt.drep[0] = DCERPC_DREP_LE;
232 0 : pkt.drep[1] = 0;
233 0 : pkt.drep[2] = 0;
234 0 : pkt.drep[3] = 0;
235 0 : pkt.frag_length = 104;
236 0 : pkt.auth_length = 0;
237 0 : pkt.call_id = 0;
238 0 : pkt.u.rts = rts;
239 :
240 0 : ndr = ndr_push_init_ctx(state);
241 0 : if (ndr == NULL) {
242 0 : return NULL;
243 : }
244 0 : ndr->offset = 0;
245 0 : ndr_push_ncacn_packet(ndr, NDR_SCALARS, &pkt);
246 :
247 0 : state->buffer = ndr_push_blob(ndr);
248 0 : state->iov.iov_base = (char *) state->buffer.data;
249 0 : state->iov.iov_len = state->buffer.length;
250 :
251 0 : stream = http_conn_tstream(roh->default_channel_in->http_conn);
252 0 : send_queue = http_conn_send_queue(roh->default_channel_in->http_conn);
253 :
254 0 : subreq = tstream_writev_queue_send(mem_ctx,
255 : ev,
256 : stream,
257 : send_queue,
258 0 : &state->iov,
259 : 1);
260 0 : if (tevent_req_nomem(subreq, req)) {
261 0 : return tevent_req_post(req, ev);
262 : }
263 0 : tevent_req_set_callback(subreq, roh_send_CONN_B1_done, req);
264 :
265 0 : return req;
266 : }
267 :
268 0 : static void roh_send_CONN_B1_done(struct tevent_req *subreq)
269 : {
270 0 : NTSTATUS status;
271 0 : struct tevent_req *req;
272 0 : struct roh_send_pdu_state *state;
273 0 : int sys_errno;
274 :
275 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
276 0 : state = tevent_req_data(req, struct roh_send_pdu_state);
277 :
278 0 : state->bytes_written = tstream_writev_queue_recv(subreq, &sys_errno);
279 0 : state->sys_errno = sys_errno;
280 0 : TALLOC_FREE(subreq);
281 0 : if (state->bytes_written <= 0 && state->sys_errno != 0) {
282 0 : status = map_nt_error_from_unix_common(sys_errno);
283 0 : tevent_req_nterror(req, status);
284 0 : return;
285 : }
286 0 : DEBUG(8, ("%s: CONN/B1 sent (%d bytes written)\n",
287 : __func__, state->bytes_written));
288 :
289 0 : tevent_req_done(req);
290 : }
291 :
292 0 : NTSTATUS roh_send_CONN_B1_recv(struct tevent_req *req)
293 : {
294 0 : NTSTATUS status;
295 :
296 0 : if (tevent_req_is_nterror(req, &status)) {
297 0 : tevent_req_received(req);
298 0 : return status;
299 : }
300 :
301 0 : tevent_req_received(req);
302 0 : return NT_STATUS_OK;
303 : }
|