OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From 8716bb5e03cc4f10e2d4edc704d8defe7e8045f1 Mon Sep 17 00:00:00 2001 |
2 | From: Stefan Metzmacher <metze@samba.org> |
||
3 | Date: Thu, 16 Jul 2015 22:46:05 +0200 |
||
4 | Subject: [PATCH 01/40] CVE-2015-5370: dcerpc.idl: add |
||
5 | DCERPC_{NCACN_PAYLOAD,FRAG}_MAX_SIZE defines |
||
6 | MIME-Version: 1.0 |
||
7 | Content-Type: text/plain; charset=UTF-8 |
||
8 | Content-Transfer-Encoding: 8bit |
||
9 | |||
10 | BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344 |
||
11 | |||
12 | Signed-off-by: Stefan Metzmacher <metze@samba.org> |
||
13 | Reviewed-by: Günther Deschner <gd@samba.org> |
||
14 | --- |
||
15 | librpc/idl/dcerpc.idl | 2 ++ |
||
16 | 1 file changed, 2 insertions(+) |
||
17 | |||
18 | --- a/librpc/idl/dcerpc.idl |
||
19 | +++ b/librpc/idl/dcerpc.idl |
||
20 | @@ -475,9 +475,11 @@ interface dcerpc |
||
21 | const uint8 DCERPC_PFC_OFFSET = 3; |
||
22 | const uint8 DCERPC_DREP_OFFSET = 4; |
||
23 | const uint8 DCERPC_FRAG_LEN_OFFSET = 8; |
||
24 | + const uint32 DCERPC_FRAG_MAX_SIZE = 5840; |
||
25 | const uint8 DCERPC_AUTH_LEN_OFFSET = 10; |
||
26 | const uint8 DCERPC_CALL_ID_OFFSET = 12; |
||
27 | const uint8 DCERPC_NCACN_PAYLOAD_OFFSET = 16; |
||
28 | + const uint32 DCERPC_NCACN_PAYLOAD_MAX_SIZE = 0x400000; /* 4 MByte */ |
||
29 | |||
30 | /* little-endian flag */ |
||
31 | const uint8 DCERPC_DREP_LE = 0x10; |
||
32 | --- a/librpc/rpc/dcerpc_util.c |
||
33 | +++ b/librpc/rpc/dcerpc_util.c |
||
34 | @@ -92,31 +92,49 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB |
||
35 | * |
||
36 | * @return - A NTSTATUS error code. |
||
37 | */ |
||
38 | -NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt, |
||
39 | +NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt, |
||
40 | TALLOC_CTX *mem_ctx, |
||
41 | - DATA_BLOB *pkt_trailer, |
||
42 | + const DATA_BLOB *pkt_trailer, |
||
43 | struct dcerpc_auth *auth, |
||
44 | - uint32_t *auth_length, |
||
45 | + uint32_t *_auth_length, |
||
46 | bool auth_data_only) |
||
47 | { |
||
48 | struct ndr_pull *ndr; |
||
49 | enum ndr_err_code ndr_err; |
||
50 | - uint32_t data_and_pad; |
||
51 | + uint16_t data_and_pad; |
||
52 | + uint16_t auth_length; |
||
53 | + uint32_t tmp_length; |
||
54 | |||
55 | - data_and_pad = pkt_trailer->length |
||
56 | - - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length); |
||
57 | + ZERO_STRUCTP(auth); |
||
58 | + if (_auth_length != NULL) { |
||
59 | + *_auth_length = 0; |
||
60 | + } |
||
61 | + |
||
62 | + /* Paranoia checks for auth_length. The caller should check this... */ |
||
63 | + if (pkt->auth_length == 0) { |
||
64 | + return NT_STATUS_INTERNAL_ERROR; |
||
65 | + } |
||
66 | + |
||
67 | + /* Paranoia checks for auth_length. The caller should check this... */ |
||
68 | + if (pkt->auth_length > pkt->frag_length) { |
||
69 | + return NT_STATUS_INTERNAL_ERROR; |
||
70 | + } |
||
71 | + tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET; |
||
72 | + tmp_length += DCERPC_AUTH_TRAILER_LENGTH; |
||
73 | + tmp_length += pkt->auth_length; |
||
74 | + if (tmp_length > pkt->frag_length) { |
||
75 | + return NT_STATUS_INTERNAL_ERROR; |
||
76 | + } |
||
77 | + if (pkt_trailer->length > UINT16_MAX) { |
||
78 | + return NT_STATUS_INTERNAL_ERROR; |
||
79 | + } |
||
80 | |||
81 | - /* paranoia check for pad size. This would be caught anyway by |
||
82 | - the ndr_pull_advance() a few lines down, but it scared |
||
83 | - Jeremy enough for him to call me, so we might as well check |
||
84 | - it now, just to prevent someone posting a bogus YouTube |
||
85 | - video in the future. |
||
86 | - */ |
||
87 | - if (data_and_pad > pkt_trailer->length) { |
||
88 | - return NT_STATUS_INFO_LENGTH_MISMATCH; |
||
89 | + auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length; |
||
90 | + if (pkt_trailer->length < auth_length) { |
||
91 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
92 | } |
||
93 | |||
94 | - *auth_length = pkt_trailer->length - data_and_pad; |
||
95 | + data_and_pad = pkt_trailer->length - auth_length; |
||
96 | |||
97 | ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx); |
||
98 | if (!ndr) { |
||
99 | @@ -136,14 +154,28 @@ NTSTATUS dcerpc_pull_auth_trailer(struct |
||
100 | ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth); |
||
101 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
||
102 | talloc_free(ndr); |
||
103 | + ZERO_STRUCTP(auth); |
||
104 | return ndr_map_error2ntstatus(ndr_err); |
||
105 | } |
||
106 | |||
107 | + if (data_and_pad < auth->auth_pad_length) { |
||
108 | + DEBUG(1, (__location__ ": ERROR: pad length mismatch. " |
||
109 | + "Calculated %u got %u\n", |
||
110 | + (unsigned)data_and_pad, |
||
111 | + (unsigned)auth->auth_pad_length)); |
||
112 | + talloc_free(ndr); |
||
113 | + ZERO_STRUCTP(auth); |
||
114 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
115 | + } |
||
116 | + |
||
117 | if (auth_data_only && data_and_pad != auth->auth_pad_length) { |
||
118 | - DEBUG(1, (__location__ ": WARNING: pad length mismatch. " |
||
119 | + DEBUG(1, (__location__ ": ERROR: pad length mismatch. " |
||
120 | "Calculated %u got %u\n", |
||
121 | (unsigned)data_and_pad, |
||
122 | (unsigned)auth->auth_pad_length)); |
||
123 | + talloc_free(ndr); |
||
124 | + ZERO_STRUCTP(auth); |
||
125 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
126 | } |
||
127 | |||
128 | DEBUG(6,(__location__ ": auth_pad_length %u\n", |
||
129 | @@ -152,6 +184,83 @@ NTSTATUS dcerpc_pull_auth_trailer(struct |
||
130 | talloc_steal(mem_ctx, auth->credentials.data); |
||
131 | talloc_free(ndr); |
||
132 | |||
133 | + if (_auth_length != NULL) { |
||
134 | + *_auth_length = auth_length; |
||
135 | + } |
||
136 | + |
||
137 | + return NT_STATUS_OK; |
||
138 | +} |
||
139 | + |
||
140 | +/** |
||
141 | +* @brief Verify the fields in ncacn_packet header. |
||
142 | +* |
||
143 | +* @param pkt - The ncacn_packet strcuture |
||
144 | +* @param ptype - The expected PDU type |
||
145 | +* @param max_auth_info - The maximum size of a possible auth trailer |
||
146 | +* @param required_flags - The required flags for the pdu. |
||
147 | +* @param optional_flags - The possible optional flags for the pdu. |
||
148 | +* |
||
149 | +* @return - A NTSTATUS error code. |
||
150 | +*/ |
||
151 | +NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, |
||
152 | + enum dcerpc_pkt_type ptype, |
||
153 | + size_t max_auth_info, |
||
154 | + uint8_t required_flags, |
||
155 | + uint8_t optional_flags) |
||
156 | +{ |
||
157 | + if (pkt->rpc_vers != 5) { |
||
158 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
159 | + } |
||
160 | + |
||
161 | + if (pkt->rpc_vers_minor != 0) { |
||
162 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
163 | + } |
||
164 | + |
||
165 | + if (pkt->auth_length > pkt->frag_length) { |
||
166 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
167 | + } |
||
168 | + |
||
169 | + if (pkt->ptype != ptype) { |
||
170 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
171 | + } |
||
172 | + |
||
173 | + if (max_auth_info > UINT16_MAX) { |
||
174 | + return NT_STATUS_INTERNAL_ERROR; |
||
175 | + } |
||
176 | + |
||
177 | + if (pkt->auth_length > 0) { |
||
178 | + size_t max_auth_length; |
||
179 | + |
||
180 | + if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) { |
||
181 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
182 | + } |
||
183 | + max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH; |
||
184 | + |
||
185 | + if (pkt->auth_length > max_auth_length) { |
||
186 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
187 | + } |
||
188 | + } |
||
189 | + |
||
190 | + if ((pkt->pfc_flags & required_flags) != required_flags) { |
||
191 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
192 | + } |
||
193 | + if (pkt->pfc_flags & ~(optional_flags|required_flags)) { |
||
194 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
195 | + } |
||
196 | + |
||
197 | + if (pkt->drep[0] & ~DCERPC_DREP_LE) { |
||
198 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
199 | + } |
||
200 | + if (pkt->drep[1] != 0) { |
||
201 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
202 | + } |
||
203 | + if (pkt->drep[2] != 0) { |
||
204 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
205 | + } |
||
206 | + if (pkt->drep[3] != 0) { |
||
207 | + return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
208 | + } |
||
209 | + |
||
210 | return NT_STATUS_OK; |
||
211 | } |
||
212 | |||
213 | --- a/librpc/rpc/rpc_common.h |
||
214 | +++ b/librpc/rpc/rpc_common.h |
||
215 | @@ -158,12 +158,17 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB |
||
216 | * |
||
217 | * @return - A NTSTATUS error code. |
||
218 | */ |
||
219 | -NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt, |
||
220 | +NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt, |
||
221 | TALLOC_CTX *mem_ctx, |
||
222 | - DATA_BLOB *pkt_trailer, |
||
223 | + const DATA_BLOB *pkt_trailer, |
||
224 | struct dcerpc_auth *auth, |
||
225 | uint32_t *auth_length, |
||
226 | bool auth_data_only); |
||
227 | +NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, |
||
228 | + enum dcerpc_pkt_type ptype, |
||
229 | + size_t max_auth_info, |
||
230 | + uint8_t required_flags, |
||
231 | + uint8_t optional_flags); |
||
232 | struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx, |
||
233 | struct tevent_context *ev, |
||
234 | struct tstream_context *stream); |
||
235 | --- a/source3/librpc/rpc/dcerpc_helpers.c |
||
236 | +++ b/source3/librpc/rpc/dcerpc_helpers.c |
||
237 | @@ -210,47 +210,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_ |
||
238 | } |
||
239 | |||
240 | /** |
||
241 | -* @brief Decodes a dcerpc_auth blob |
||
242 | -* |
||
243 | -* @param mem_ctx The memory context on which to allocate the packet |
||
244 | -* elements |
||
245 | -* @param blob The blob of data to decode |
||
246 | -* @param r An empty dcerpc_auth structure, must not be NULL |
||
247 | -* |
||
248 | -* @return a NTSTATUS error code |
||
249 | -*/ |
||
250 | -NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, |
||
251 | - const DATA_BLOB *blob, |
||
252 | - struct dcerpc_auth *r, |
||
253 | - bool bigendian) |
||
254 | -{ |
||
255 | - enum ndr_err_code ndr_err; |
||
256 | - struct ndr_pull *ndr; |
||
257 | - |
||
258 | - ndr = ndr_pull_init_blob(blob, mem_ctx); |
||
259 | - if (!ndr) { |
||
260 | - return NT_STATUS_NO_MEMORY; |
||
261 | - } |
||
262 | - if (bigendian) { |
||
263 | - ndr->flags |= LIBNDR_FLAG_BIGENDIAN; |
||
264 | - } |
||
265 | - |
||
266 | - ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r); |
||
267 | - |
||
268 | - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
||
269 | - talloc_free(ndr); |
||
270 | - return ndr_map_error2ntstatus(ndr_err); |
||
271 | - } |
||
272 | - talloc_free(ndr); |
||
273 | - |
||
274 | - if (DEBUGLEVEL >= 10) { |
||
275 | - NDR_PRINT_DEBUG(dcerpc_auth, r); |
||
276 | - } |
||
277 | - |
||
278 | - return NT_STATUS_OK; |
||
279 | -} |
||
280 | - |
||
281 | -/** |
||
282 | * @brief Calculate how much data we can in a packet, including calculating |
||
283 | * auth token and pad lengths. |
||
284 | * |
||
285 | @@ -782,7 +741,7 @@ NTSTATUS dcerpc_add_auth_footer(struct p |
||
286 | auth->auth_type, |
||
287 | auth->auth_level, |
||
288 | pad_len, |
||
289 | - 1 /* context id. */, |
||
290 | + auth->auth_context_id, |
||
291 | &auth_blob, |
||
292 | &auth_info); |
||
293 | if (!NT_STATUS_IS_OK(status)) { |
||
294 | @@ -844,19 +803,18 @@ NTSTATUS dcerpc_add_auth_footer(struct p |
||
295 | * |
||
296 | * @param auth The auth data for the connection |
||
297 | * @param pkt The actual ncacn_packet |
||
298 | -* @param pkt_trailer The stub_and_verifier part of the packet |
||
299 | +* @param pkt_trailer [in][out] The stub_and_verifier part of the packet, |
||
300 | +* the auth_trailer and padding will be removed. |
||
301 | * @param header_size The header size |
||
302 | * @param raw_pkt The whole raw packet data blob |
||
303 | -* @param pad_len [out] The padding length used in the packet |
||
304 | * |
||
305 | * @return A NTSTATUS error code |
||
306 | */ |
||
307 | NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, |
||
308 | struct ncacn_packet *pkt, |
||
309 | DATA_BLOB *pkt_trailer, |
||
310 | - size_t header_size, |
||
311 | - DATA_BLOB *raw_pkt, |
||
312 | - size_t *pad_len) |
||
313 | + uint8_t header_size, |
||
314 | + DATA_BLOB *raw_pkt) |
||
315 | { |
||
316 | struct schannel_state *schannel_auth; |
||
317 | struct auth_ntlmssp_state *ntlmssp_ctx; |
||
318 | @@ -868,6 +826,14 @@ NTSTATUS dcerpc_check_auth(struct pipe_a |
||
319 | DATA_BLOB full_pkt; |
||
320 | DATA_BLOB data; |
||
321 | |||
322 | + /* |
||
323 | + * These check should be done in the caller. |
||
324 | + */ |
||
325 | + SMB_ASSERT(raw_pkt->length == pkt->frag_length); |
||
326 | + SMB_ASSERT(header_size <= pkt->frag_length); |
||
327 | + SMB_ASSERT(pkt_trailer->length < pkt->frag_length); |
||
328 | + SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length); |
||
329 | + |
||
330 | switch (auth->auth_level) { |
||
331 | case DCERPC_AUTH_LEVEL_PRIVACY: |
||
332 | DEBUG(10, ("Requested Privacy.\n")); |
||
333 | @@ -881,7 +847,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_a |
||
334 | if (pkt->auth_length != 0) { |
||
335 | break; |
||
336 | } |
||
337 | - *pad_len = 0; |
||
338 | return NT_STATUS_OK; |
||
339 | |||
340 | case DCERPC_AUTH_LEVEL_NONE: |
||
341 | @@ -890,7 +855,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_a |
||
342 | "authenticated connection!\n")); |
||
343 | return NT_STATUS_INVALID_PARAMETER; |
||
344 | } |
||
345 | - *pad_len = 0; |
||
346 | return NT_STATUS_OK; |
||
347 | |||
348 | default: |
||
349 | @@ -899,16 +863,8 @@ NTSTATUS dcerpc_check_auth(struct pipe_a |
||
350 | return NT_STATUS_INVALID_PARAMETER; |
||
351 | } |
||
352 | |||
353 | - /* Paranioa checks for auth_length. */ |
||
354 | - if (pkt->auth_length > pkt->frag_length) { |
||
355 | - return NT_STATUS_INFO_LENGTH_MISMATCH; |
||
356 | - } |
||
357 | - if (((unsigned int)pkt->auth_length |
||
358 | - + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) || |
||
359 | - ((unsigned int)pkt->auth_length |
||
360 | - + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) { |
||
361 | - /* Integer wrap attempt. */ |
||
362 | - return NT_STATUS_INFO_LENGTH_MISMATCH; |
||
363 | + if (pkt->auth_length == 0) { |
||
364 | + return NT_STATUS_INVALID_PARAMETER; |
||
365 | } |
||
366 | |||
367 | status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer, |
||
368 | @@ -917,10 +873,23 @@ NTSTATUS dcerpc_check_auth(struct pipe_a |
||
369 | return status; |
||
370 | } |
||
371 | |||
372 | + if (auth_info.auth_type != auth->auth_type) { |
||
373 | + return NT_STATUS_INVALID_PARAMETER; |
||
374 | + } |
||
375 | + |
||
376 | + if (auth_info.auth_level != auth->auth_level) { |
||
377 | + return NT_STATUS_INVALID_PARAMETER; |
||
378 | + } |
||
379 | + |
||
380 | + if (auth_info.auth_context_id != auth->auth_context_id) { |
||
381 | + return NT_STATUS_INVALID_PARAMETER; |
||
382 | + } |
||
383 | + |
||
384 | + pkt_trailer->length -= auth_length; |
||
385 | data = data_blob_const(raw_pkt->data + header_size, |
||
386 | - pkt_trailer->length - auth_length); |
||
387 | - full_pkt = data_blob_const(raw_pkt->data, |
||
388 | - raw_pkt->length - auth_info.credentials.length); |
||
389 | + pkt_trailer->length); |
||
390 | + full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length); |
||
391 | + full_pkt.length -= auth_info.credentials.length; |
||
392 | |||
393 | switch (auth->auth_type) { |
||
394 | case DCERPC_AUTH_TYPE_NONE: |
||
395 | @@ -996,10 +965,13 @@ NTSTATUS dcerpc_check_auth(struct pipe_a |
||
396 | * pkt_trailer actually has a copy of the raw data, and they |
||
397 | * are still both used in later calls */ |
||
398 | if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { |
||
399 | + if (pkt_trailer->length != data.length) { |
||
400 | + return NT_STATUS_INVALID_PARAMETER; |
||
401 | + } |
||
402 | memcpy(pkt_trailer->data, data.data, data.length); |
||
403 | } |
||
404 | |||
405 | - *pad_len = auth_info.auth_pad_length; |
||
406 | + pkt_trailer->length -= auth_info.auth_pad_length; |
||
407 | data_blob_free(&auth_info.credentials); |
||
408 | return NT_STATUS_OK; |
||
409 | } |
||
410 | --- a/source3/rpc_client/cli_pipe.c |
||
411 | +++ b/source3/rpc_client/cli_pipe.c |
||
412 | @@ -404,9 +404,9 @@ static NTSTATUS cli_pipe_validate_curren |
||
413 | DATA_BLOB *rdata, |
||
414 | DATA_BLOB *reply_pdu) |
||
415 | { |
||
416 | - struct dcerpc_response *r; |
||
417 | + const struct dcerpc_response *r = NULL; |
||
418 | + DATA_BLOB tmp_stub = data_blob_null; |
||
419 | NTSTATUS ret = NT_STATUS_OK; |
||
420 | - size_t pad_len = 0; |
||
421 | |||
422 | /* |
||
423 | * Point the return values at the real data including the RPC |
||
424 | @@ -414,50 +414,128 @@ static NTSTATUS cli_pipe_validate_curren |
||
425 | */ |
||
426 | *rdata = *pdu; |
||
427 | |||
428 | + if ((pkt->ptype == DCERPC_PKT_BIND_ACK) && |
||
429 | + !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) { |
||
430 | + /* |
||
431 | + * TODO: do we still need this hack which was introduced |
||
432 | + * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0. |
||
433 | + * |
||
434 | + * I don't even know what AS/U might be... |
||
435 | + */ |
||
436 | + DEBUG(5, (__location__ ": bug in server (AS/U?), setting " |
||
437 | + "fragment first/last ON.\n")); |
||
438 | + pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; |
||
439 | + } |
||
440 | + |
||
441 | /* Ensure we have the correct type. */ |
||
442 | switch (pkt->ptype) { |
||
443 | - case DCERPC_PKT_ALTER_RESP: |
||
444 | + case DCERPC_PKT_BIND_NAK: |
||
445 | + DEBUG(1, (__location__ ": Bind NACK received from %s!\n", |
||
446 | + rpccli_pipe_txt(talloc_tos(), cli))); |
||
447 | + |
||
448 | + ret = dcerpc_verify_ncacn_packet_header(pkt, |
||
449 | + DCERPC_PKT_BIND_NAK, |
||
450 | + 0, /* max_auth_info */ |
||
451 | + DCERPC_PFC_FLAG_FIRST | |
||
452 | + DCERPC_PFC_FLAG_LAST, |
||
453 | + 0); /* optional flags */ |
||
454 | + if (!NT_STATUS_IS_OK(ret)) { |
||
455 | + DEBUG(1, (__location__ ": Connection to %s got an unexpected " |
||
456 | + "RPC packet type - %u, expected %u: %s\n", |
||
457 | + rpccli_pipe_txt(talloc_tos(), cli), |
||
458 | + pkt->ptype, expected_pkt_type, |
||
459 | + nt_errstr(ret))); |
||
460 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
461 | + return ret; |
||
462 | + } |
||
463 | + |
||
464 | + /* Use this for now... */ |
||
465 | + return NT_STATUS_NETWORK_ACCESS_DENIED; |
||
466 | + |
||
467 | case DCERPC_PKT_BIND_ACK: |
||
468 | + ret = dcerpc_verify_ncacn_packet_header(pkt, |
||
469 | + expected_pkt_type, |
||
470 | + pkt->u.bind_ack.auth_info.length, |
||
471 | + DCERPC_PFC_FLAG_FIRST | |
||
472 | + DCERPC_PFC_FLAG_LAST, |
||
473 | + DCERPC_PFC_FLAG_CONC_MPX | |
||
474 | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN); |
||
475 | + if (!NT_STATUS_IS_OK(ret)) { |
||
476 | + DEBUG(1, (__location__ ": Connection to %s got an unexpected " |
||
477 | + "RPC packet type - %u, expected %u: %s\n", |
||
478 | + rpccli_pipe_txt(talloc_tos(), cli), |
||
479 | + pkt->ptype, expected_pkt_type, |
||
480 | + nt_errstr(ret))); |
||
481 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
482 | + return ret; |
||
483 | + } |
||
484 | |||
485 | - /* Client code never receives this kind of packets */ |
||
486 | break; |
||
487 | |||
488 | + case DCERPC_PKT_ALTER_RESP: |
||
489 | + ret = dcerpc_verify_ncacn_packet_header(pkt, |
||
490 | + expected_pkt_type, |
||
491 | + pkt->u.alter_resp.auth_info.length, |
||
492 | + DCERPC_PFC_FLAG_FIRST | |
||
493 | + DCERPC_PFC_FLAG_LAST, |
||
494 | + DCERPC_PFC_FLAG_CONC_MPX | |
||
495 | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN); |
||
496 | + if (!NT_STATUS_IS_OK(ret)) { |
||
497 | + DEBUG(1, (__location__ ": Connection to %s got an unexpected " |
||
498 | + "RPC packet type - %u, expected %u: %s\n", |
||
499 | + rpccli_pipe_txt(talloc_tos(), cli), |
||
500 | + pkt->ptype, expected_pkt_type, |
||
501 | + nt_errstr(ret))); |
||
502 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
503 | + return ret; |
||
504 | + } |
||
505 | + |
||
506 | + break; |
||
507 | |||
508 | case DCERPC_PKT_RESPONSE: |
||
509 | |||
510 | r = &pkt->u.response; |
||
511 | |||
512 | + ret = dcerpc_verify_ncacn_packet_header(pkt, |
||
513 | + expected_pkt_type, |
||
514 | + r->stub_and_verifier.length, |
||
515 | + 0, /* required_flags */ |
||
516 | + DCERPC_PFC_FLAG_FIRST | |
||
517 | + DCERPC_PFC_FLAG_LAST); |
||
518 | + if (!NT_STATUS_IS_OK(ret)) { |
||
519 | + DEBUG(1, (__location__ ": Connection to %s got an unexpected " |
||
520 | + "RPC packet type - %u, expected %u: %s\n", |
||
521 | + rpccli_pipe_txt(talloc_tos(), cli), |
||
522 | + pkt->ptype, expected_pkt_type, |
||
523 | + nt_errstr(ret))); |
||
524 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
525 | + return ret; |
||
526 | + } |
||
527 | + |
||
528 | + tmp_stub.data = r->stub_and_verifier.data; |
||
529 | + tmp_stub.length = r->stub_and_verifier.length; |
||
530 | + |
||
531 | /* Here's where we deal with incoming sign/seal. */ |
||
532 | ret = dcerpc_check_auth(cli->auth, pkt, |
||
533 | - &r->stub_and_verifier, |
||
534 | + &tmp_stub, |
||
535 | DCERPC_RESPONSE_LENGTH, |
||
536 | - pdu, &pad_len); |
||
537 | + pdu); |
||
538 | if (!NT_STATUS_IS_OK(ret)) { |
||
539 | + DEBUG(1, (__location__ ": Connection to %s got an unexpected " |
||
540 | + "RPC packet type - %u, expected %u: %s\n", |
||
541 | + rpccli_pipe_txt(talloc_tos(), cli), |
||
542 | + pkt->ptype, expected_pkt_type, |
||
543 | + nt_errstr(ret))); |
||
544 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
545 | return ret; |
||
546 | } |
||
547 | |||
548 | - if (pkt->frag_length < DCERPC_RESPONSE_LENGTH + pad_len) { |
||
549 | - return NT_STATUS_BUFFER_TOO_SMALL; |
||
550 | - } |
||
551 | - |
||
552 | /* Point the return values at the NDR data. */ |
||
553 | - rdata->data = r->stub_and_verifier.data; |
||
554 | + *rdata = tmp_stub; |
||
555 | |||
556 | - if (pkt->auth_length) { |
||
557 | - /* We've already done integer wrap tests in |
||
558 | - * dcerpc_check_auth(). */ |
||
559 | - rdata->length = r->stub_and_verifier.length |
||
560 | - - pad_len |
||
561 | - - DCERPC_AUTH_TRAILER_LENGTH |
||
562 | - - pkt->auth_length; |
||
563 | - } else { |
||
564 | - rdata->length = r->stub_and_verifier.length; |
||
565 | - } |
||
566 | - |
||
567 | - DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n", |
||
568 | + DEBUG(10, ("Got pdu len %lu, data_len %lu\n", |
||
569 | (long unsigned int)pdu->length, |
||
570 | - (long unsigned int)rdata->length, |
||
571 | - (unsigned int)pad_len)); |
||
572 | + (long unsigned int)rdata->length)); |
||
573 | |||
574 | /* |
||
575 | * If this is the first reply, and the allocation hint is |
||
576 | @@ -478,14 +556,24 @@ static NTSTATUS cli_pipe_validate_curren |
||
577 | |||
578 | break; |
||
579 | |||
580 | - case DCERPC_PKT_BIND_NAK: |
||
581 | - DEBUG(1, (__location__ ": Bind NACK received from %s!\n", |
||
582 | - rpccli_pipe_txt(talloc_tos(), cli))); |
||
583 | - /* Use this for now... */ |
||
584 | - return NT_STATUS_NETWORK_ACCESS_DENIED; |
||
585 | - |
||
586 | case DCERPC_PKT_FAULT: |
||
587 | |||
588 | + ret = dcerpc_verify_ncacn_packet_header(pkt, |
||
589 | + DCERPC_PKT_FAULT, |
||
590 | + 0, /* max_auth_info */ |
||
591 | + DCERPC_PFC_FLAG_FIRST | |
||
592 | + DCERPC_PFC_FLAG_LAST, |
||
593 | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE); |
||
594 | + if (!NT_STATUS_IS_OK(ret)) { |
||
595 | + DEBUG(1, (__location__ ": Connection to %s got an unexpected " |
||
596 | + "RPC packet type - %u, expected %u: %s\n", |
||
597 | + rpccli_pipe_txt(talloc_tos(), cli), |
||
598 | + pkt->ptype, expected_pkt_type, |
||
599 | + nt_errstr(ret))); |
||
600 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
601 | + return ret; |
||
602 | + } |
||
603 | + |
||
604 | DEBUG(1, (__location__ ": RPC fault code %s received " |
||
605 | "from %s!\n", |
||
606 | dcerpc_errstr(talloc_tos(), |
||
607 | @@ -502,13 +590,6 @@ static NTSTATUS cli_pipe_validate_curren |
||
608 | return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
609 | } |
||
610 | |||
611 | - if (pkt->ptype != expected_pkt_type) { |
||
612 | - DEBUG(3, (__location__ ": Connection to %s got an unexpected " |
||
613 | - "RPC packet type - %u, not %u\n", |
||
614 | - rpccli_pipe_txt(talloc_tos(), cli), |
||
615 | - pkt->ptype, expected_pkt_type)); |
||
616 | - return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
617 | - } |
||
618 | |||
619 | if (pkt->call_id != call_id) { |
||
620 | DEBUG(3, (__location__ ": Connection to %s got an unexpected " |
||
621 | @@ -518,17 +599,6 @@ static NTSTATUS cli_pipe_validate_curren |
||
622 | return NT_STATUS_RPC_PROTOCOL_ERROR; |
||
623 | } |
||
624 | |||
625 | - /* Do this just before return - we don't want to modify any rpc header |
||
626 | - data before now as we may have needed to do cryptographic actions on |
||
627 | - it before. */ |
||
628 | - |
||
629 | - if ((pkt->ptype == DCERPC_PKT_BIND_ACK) && |
||
630 | - !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) { |
||
631 | - DEBUG(5, (__location__ ": bug in server (AS/U?), setting " |
||
632 | - "fragment first/last ON.\n")); |
||
633 | - pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; |
||
634 | - } |
||
635 | - |
||
636 | return NT_STATUS_OK; |
||
637 | } |
||
638 | |||
639 | @@ -883,6 +953,12 @@ static void rpc_api_pipe_got_pdu(struct |
||
640 | |||
641 | state->pkt = talloc(state, struct ncacn_packet); |
||
642 | if (!state->pkt) { |
||
643 | + /* |
||
644 | + * TODO: do a real async disconnect ... |
||
645 | + * |
||
646 | + * For now do it sync... |
||
647 | + */ |
||
648 | + TALLOC_FREE(state->cli->transport); |
||
649 | tevent_req_nterror(req, NT_STATUS_NO_MEMORY); |
||
650 | return; |
||
651 | } |
||
652 | @@ -892,18 +968,16 @@ static void rpc_api_pipe_got_pdu(struct |
||
653 | state->pkt, |
||
654 | !state->endianess); |
||
655 | if (!NT_STATUS_IS_OK(status)) { |
||
656 | + /* |
||
657 | + * TODO: do a real async disconnect ... |
||
658 | + * |
||
659 | + * For now do it sync... |
||
660 | + */ |
||
661 | + TALLOC_FREE(state->cli->transport); |
||
662 | tevent_req_nterror(req, status); |
||
663 | return; |
||
664 | } |
||
665 | |||
666 | - if (state->incoming_frag.length != state->pkt->frag_length) { |
||
667 | - DEBUG(5, ("Incorrect pdu length %u, expected %u\n", |
||
668 | - (unsigned int)state->incoming_frag.length, |
||
669 | - (unsigned int)state->pkt->frag_length)); |
||
670 | - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); |
||
671 | - return; |
||
672 | - } |
||
673 | - |
||
674 | status = cli_pipe_validate_current_pdu(state, |
||
675 | state->cli, state->pkt, |
||
676 | &state->incoming_frag, |
||
677 | @@ -917,6 +991,28 @@ static void rpc_api_pipe_got_pdu(struct |
||
678 | (unsigned)state->reply_pdu_offset, |
||
679 | nt_errstr(status))); |
||
680 | |||
681 | + if (state->pkt->ptype != DCERPC_PKT_FAULT && !NT_STATUS_IS_OK(status)) { |
||
682 | + /* |
||
683 | + * TODO: do a real async disconnect ... |
||
684 | + * |
||
685 | + * For now do it sync... |
||
686 | + */ |
||
687 | + TALLOC_FREE(state->cli->transport); |
||
688 | + } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) { |
||
689 | + /* |
||
690 | + * TODO: do a real async disconnect ... |
||
691 | + * |
||
692 | + * For now do it sync... |
||
693 | + */ |
||
694 | + TALLOC_FREE(state->cli->transport); |
||
695 | + } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) { |
||
696 | + /* |
||
697 | + * TODO: do a real async disconnect ... |
||
698 | + * |
||
699 | + * For now do it sync... |
||
700 | + */ |
||
701 | + TALLOC_FREE(state->cli->transport); |
||
702 | + } |
||
703 | if (!NT_STATUS_IS_OK(status)) { |
||
704 | tevent_req_nterror(req, status); |
||
705 | return; |
||
706 | @@ -941,7 +1037,24 @@ static void rpc_api_pipe_got_pdu(struct |
||
707 | "%s\n", |
||
708 | state->endianess?"little":"big", |
||
709 | state->pkt->drep[0]?"little":"big")); |
||
710 | - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); |
||
711 | + /* |
||
712 | + * TODO: do a real async disconnect ... |
||
713 | + * |
||
714 | + * For now do it sync... |
||
715 | + */ |
||
716 | + TALLOC_FREE(state->cli->transport); |
||
717 | + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); |
||
718 | + return; |
||
719 | + } |
||
720 | + |
||
721 | + if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) { |
||
722 | + /* |
||
723 | + * TODO: do a real async disconnect ... |
||
724 | + * |
||
725 | + * For now do it sync... |
||
726 | + */ |
||
727 | + TALLOC_FREE(state->cli->transport); |
||
728 | + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); |
||
729 | return; |
||
730 | } |
||
731 | |||
732 | @@ -949,6 +1062,12 @@ static void rpc_api_pipe_got_pdu(struct |
||
733 | if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) { |
||
734 | if (!data_blob_realloc(NULL, &state->reply_pdu, |
||
735 | state->reply_pdu_offset + rdata.length)) { |
||
736 | + /* |
||
737 | + * TODO: do a real async disconnect ... |
||
738 | + * |
||
739 | + * For now do it sync... |
||
740 | + */ |
||
741 | + TALLOC_FREE(state->cli->transport); |
||
742 | tevent_req_nterror(req, NT_STATUS_NO_MEMORY); |
||
743 | return; |
||
744 | } |
||
745 | @@ -978,6 +1097,14 @@ static void rpc_api_pipe_got_pdu(struct |
||
746 | subreq = get_complete_frag_send(state, state->ev, state->cli, |
||
747 | state->call_id, |
||
748 | &state->incoming_frag); |
||
749 | + if (subreq == NULL) { |
||
750 | + /* |
||
751 | + * TODO: do a real async disconnect ... |
||
752 | + * |
||
753 | + * For now do it sync... |
||
754 | + */ |
||
755 | + TALLOC_FREE(state->cli->transport); |
||
756 | + } |
||
757 | if (tevent_req_nomem(subreq, req)) { |
||
758 | return; |
||
759 | } |
||
760 | @@ -1247,7 +1374,7 @@ static NTSTATUS create_rpc_bind_req(TALL |
||
761 | auth->auth_type, |
||
762 | auth->auth_level, |
||
763 | 0, /* auth_pad_length */ |
||
764 | - 1, /* auth_context_id */ |
||
765 | + auth->auth_context_id, |
||
766 | &auth_token, |
||
767 | &auth_info); |
||
768 | if (!NT_STATUS_IS_OK(ret)) { |
||
769 | @@ -1749,9 +1876,8 @@ static bool check_bind_response(const st |
||
770 | |||
771 | static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx, |
||
772 | struct rpc_pipe_client *cli, |
||
773 | - uint32 rpc_call_id, |
||
774 | - enum dcerpc_AuthType auth_type, |
||
775 | - enum dcerpc_AuthLevel auth_level, |
||
776 | + struct pipe_auth_data *auth, |
||
777 | + uint32_t rpc_call_id, |
||
778 | DATA_BLOB *pauth_blob, |
||
779 | DATA_BLOB *rpc_out) |
||
780 | { |
||
781 | @@ -1761,10 +1887,10 @@ static NTSTATUS create_rpc_bind_auth3(TA |
||
782 | u.auth3._pad = 0; |
||
783 | |||
784 | status = dcerpc_push_dcerpc_auth(mem_ctx, |
||
785 | - auth_type, |
||
786 | - auth_level, |
||
787 | + auth->auth_type, |
||
788 | + auth->auth_level, |
||
789 | 0, /* auth_pad_length */ |
||
790 | - 1, /* auth_context_id */ |
||
791 | + auth->auth_context_id, |
||
792 | pauth_blob, |
||
793 | &u.auth3.auth_info); |
||
794 | if (!NT_STATUS_IS_OK(status)) { |
||
795 | @@ -1794,9 +1920,8 @@ static NTSTATUS create_rpc_bind_auth3(TA |
||
796 | ********************************************************************/ |
||
797 | |||
798 | static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx, |
||
799 | - enum dcerpc_AuthType auth_type, |
||
800 | - enum dcerpc_AuthLevel auth_level, |
||
801 | - uint32 rpc_call_id, |
||
802 | + struct pipe_auth_data *auth, |
||
803 | + uint32_t rpc_call_id, |
||
804 | const struct ndr_syntax_id *abstract, |
||
805 | const struct ndr_syntax_id *transfer, |
||
806 | const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */ |
||
807 | @@ -1806,10 +1931,10 @@ static NTSTATUS create_rpc_alter_context |
||
808 | NTSTATUS status; |
||
809 | |||
810 | status = dcerpc_push_dcerpc_auth(mem_ctx, |
||
811 | - auth_type, |
||
812 | - auth_level, |
||
813 | + auth->auth_type, |
||
814 | + auth->auth_level, |
||
815 | 0, /* auth_pad_length */ |
||
816 | - 1, /* auth_context_id */ |
||
817 | + auth->auth_context_id, |
||
818 | pauth_blob, |
||
819 | &auth_info); |
||
820 | if (!NT_STATUS_IS_OK(status)) { |
||
821 | @@ -1957,30 +2082,45 @@ static void rpc_pipe_bind_step_one_done( |
||
822 | rpc_pipe_bind_step_two_trigger(req); |
||
823 | return; |
||
824 | |||
825 | - case DCERPC_AUTH_TYPE_NTLMSSP: |
||
826 | - case DCERPC_AUTH_TYPE_SPNEGO: |
||
827 | - case DCERPC_AUTH_TYPE_KRB5: |
||
828 | - /* Paranoid lenght checks */ |
||
829 | - if (pkt->frag_length < DCERPC_AUTH_TRAILER_LENGTH |
||
830 | - + pkt->auth_length) { |
||
831 | - tevent_req_nterror(req, |
||
832 | - NT_STATUS_INFO_LENGTH_MISMATCH); |
||
833 | + default: |
||
834 | + if (pkt->auth_length == 0) { |
||
835 | + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); |
||
836 | return; |
||
837 | } |
||
838 | /* get auth credentials */ |
||
839 | - status = dcerpc_pull_dcerpc_auth(talloc_tos(), |
||
840 | - &pkt->u.bind_ack.auth_info, |
||
841 | - &auth, false); |
||
842 | + status = dcerpc_pull_auth_trailer(pkt, talloc_tos(), |
||
843 | + &pkt->u.bind_ack.auth_info, |
||
844 | + &auth, NULL, true); |
||
845 | if (!NT_STATUS_IS_OK(status)) { |
||
846 | DEBUG(0, ("Failed to pull dcerpc auth: %s.\n", |
||
847 | nt_errstr(status))); |
||
848 | tevent_req_nterror(req, status); |
||
849 | return; |
||
850 | } |
||
851 | - break; |
||
852 | |||
853 | - default: |
||
854 | - goto err_out; |
||
855 | + if (auth.auth_type != pauth->auth_type) { |
||
856 | + DEBUG(0, (__location__ " Auth type %u mismatch expected %u.\n", |
||
857 | + auth.auth_type, pauth->auth_type)); |
||
858 | + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); |
||
859 | + return; |
||
860 | + } |
||
861 | + |
||
862 | + if (auth.auth_level != pauth->auth_level) { |
||
863 | + DEBUG(0, (__location__ " Auth level %u mismatch expected %u.\n", |
||
864 | + auth.auth_level, pauth->auth_level)); |
||
865 | + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); |
||
866 | + return; |
||
867 | + } |
||
868 | + |
||
869 | + if (auth.auth_context_id != pauth->auth_context_id) { |
||
870 | + DEBUG(0, (__location__ " Auth context id %u mismatch expected %u.\n", |
||
871 | + (unsigned)auth.auth_context_id, |
||
872 | + (unsigned)pauth->auth_context_id)); |
||
873 | + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); |
||
874 | + return; |
||
875 | + } |
||
876 | + |
||
877 | + break; |
||
878 | } |
||
879 | |||
880 | /* |
||
881 | @@ -2226,9 +2366,7 @@ static NTSTATUS rpc_bind_next_send(struc |
||
882 | /* Now prepare the alter context pdu. */ |
||
883 | data_blob_free(&state->rpc_out); |
||
884 | |||
885 | - status = create_rpc_alter_context(state, |
||
886 | - auth->auth_type, |
||
887 | - auth->auth_level, |
||
888 | + status = create_rpc_alter_context(state, auth, |
||
889 | state->rpc_call_id, |
||
890 | &state->cli->abstract_syntax, |
||
891 | &state->cli->transfer_syntax, |
||
892 | @@ -2261,10 +2399,8 @@ static NTSTATUS rpc_bind_finish_send(str |
||
893 | /* Now prepare the auth3 context pdu. */ |
||
894 | data_blob_free(&state->rpc_out); |
||
895 | |||
896 | - status = create_rpc_bind_auth3(state, state->cli, |
||
897 | + status = create_rpc_bind_auth3(state, state->cli, auth, |
||
898 | state->rpc_call_id, |
||
899 | - auth->auth_type, |
||
900 | - auth->auth_level, |
||
901 | auth_token, |
||
902 | &state->rpc_out); |
||
903 | if (!NT_STATUS_IS_OK(status)) { |
||
904 | @@ -2498,8 +2634,9 @@ static struct tevent_req *rpccli_bh_disc |
||
905 | /* |
||
906 | * TODO: do a real async disconnect ... |
||
907 | * |
||
908 | - * For now the caller needs to free rpc_cli |
||
909 | + * For now we do it sync... |
||
910 | */ |
||
911 | + TALLOC_FREE(hs->rpc_cli->transport); |
||
912 | hs->rpc_cli = NULL; |
||
913 | |||
914 | tevent_req_done(req); |
||
915 | @@ -2636,6 +2773,7 @@ NTSTATUS rpccli_ncalrpc_bind_data(TALLOC |
||
916 | |||
917 | result->auth_type = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM; |
||
918 | result->auth_level = DCERPC_AUTH_LEVEL_CONNECT; |
||
919 | + result->auth_context_id = 1; |
||
920 | |||
921 | result->user_name = talloc_strdup(result, ""); |
||
922 | result->domain = talloc_strdup(result, ""); |
||
923 | @@ -2660,6 +2798,7 @@ NTSTATUS rpccli_anon_bind_data(TALLOC_CT |
||
924 | |||
925 | result->auth_type = DCERPC_AUTH_TYPE_NONE; |
||
926 | result->auth_level = DCERPC_AUTH_LEVEL_NONE; |
||
927 | + result->auth_context_id = 0; |
||
928 | |||
929 | result->user_name = talloc_strdup(result, ""); |
||
930 | result->domain = talloc_strdup(result, ""); |
||
931 | @@ -2697,6 +2836,7 @@ static NTSTATUS rpccli_ntlmssp_bind_data |
||
932 | |||
933 | result->auth_type = auth_type; |
||
934 | result->auth_level = auth_level; |
||
935 | + result->auth_context_id = 1; |
||
936 | |||
937 | result->user_name = talloc_strdup(result, username); |
||
938 | result->domain = talloc_strdup(result, domain); |
||
939 | @@ -2768,6 +2908,7 @@ NTSTATUS rpccli_schannel_bind_data(TALLO |
||
940 | |||
941 | result->auth_type = DCERPC_AUTH_TYPE_SCHANNEL; |
||
942 | result->auth_level = auth_level; |
||
943 | + result->auth_context_id = 1; |
||
944 | |||
945 | result->user_name = talloc_strdup(result, ""); |
||
946 | result->domain = talloc_strdup(result, domain); |
||
947 | @@ -3432,6 +3573,7 @@ NTSTATUS cli_rpc_pipe_open_krb5(struct c |
||
948 | } |
||
949 | auth->auth_type = DCERPC_AUTH_TYPE_KRB5; |
||
950 | auth->auth_level = auth_level; |
||
951 | + auth->auth_context_id = 1; |
||
952 | |||
953 | if (!username) { |
||
954 | username = ""; |
||
955 | @@ -3502,6 +3644,7 @@ NTSTATUS cli_rpc_pipe_open_spnego_krb5(s |
||
956 | } |
||
957 | auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO; |
||
958 | auth->auth_level = auth_level; |
||
959 | + auth->auth_context_id = 1; |
||
960 | |||
961 | if (!username) { |
||
962 | username = ""; |
||
963 | @@ -3576,6 +3719,7 @@ NTSTATUS cli_rpc_pipe_open_spnego_ntlmss |
||
964 | } |
||
965 | auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO; |
||
966 | auth->auth_level = auth_level; |
||
967 | + auth->auth_context_id = 1; |
||
968 | |||
969 | if (!username) { |
||
970 | username = ""; |
||
971 | --- a/source4/rpc_server/dcesrv_auth.c |
||
972 | +++ b/source4/rpc_server/dcesrv_auth.c |
||
973 | @@ -46,7 +46,7 @@ bool dcesrv_auth_bind(struct dcesrv_call |
||
974 | NTSTATUS status; |
||
975 | uint32_t auth_length; |
||
976 | |||
977 | - if (pkt->u.bind.auth_info.length == 0) { |
||
978 | + if (pkt->auth_length == 0) { |
||
979 | dce_conn->auth_state.auth_info = NULL; |
||
980 | return true; |
||
981 | } |
||
982 | @@ -108,7 +108,7 @@ NTSTATUS dcesrv_auth_bind_ack(struct dce |
||
983 | struct dcesrv_connection *dce_conn = call->conn; |
||
984 | NTSTATUS status; |
||
985 | |||
986 | - if (!call->conn->auth_state.gensec_security) { |
||
987 | + if (call->pkt.auth_length == 0) { |
||
988 | return NT_STATUS_OK; |
||
989 | } |
||
990 | |||
991 | @@ -155,10 +155,16 @@ bool dcesrv_auth_auth3(struct dcesrv_cal |
||
992 | NTSTATUS status; |
||
993 | uint32_t auth_length; |
||
994 | |||
995 | - /* We can't work without an existing gensec state, and an new blob to feed it */ |
||
996 | - if (!dce_conn->auth_state.auth_info || |
||
997 | - !dce_conn->auth_state.gensec_security || |
||
998 | - pkt->u.auth3.auth_info.length == 0) { |
||
999 | + if (pkt->auth_length == 0) { |
||
1000 | + return false; |
||
1001 | + } |
||
1002 | + |
||
1003 | + if (!dce_conn->auth_state.auth_info) { |
||
1004 | + return false; |
||
1005 | + } |
||
1006 | + |
||
1007 | + /* We can't work without an existing gensec state */ |
||
1008 | + if (!dce_conn->auth_state.gensec_security) { |
||
1009 | return false; |
||
1010 | } |
||
1011 | |||
1012 | @@ -203,7 +209,7 @@ bool dcesrv_auth_alter(struct dcesrv_cal |
||
1013 | uint32_t auth_length; |
||
1014 | |||
1015 | /* on a pure interface change there is no auth blob */ |
||
1016 | - if (pkt->u.alter.auth_info.length == 0) { |
||
1017 | + if (pkt->auth_length == 0) { |
||
1018 | return true; |
||
1019 | } |
||
1020 | |||
1021 | @@ -238,8 +244,7 @@ NTSTATUS dcesrv_auth_alter_ack(struct dc |
||
1022 | |||
1023 | /* on a pure interface change there is no auth_info structure |
||
1024 | setup */ |
||
1025 | - if (!call->conn->auth_state.auth_info || |
||
1026 | - dce_conn->auth_state.auth_info->credentials.length == 0) { |
||
1027 | + if (call->pkt.auth_length == 0) { |
||
1028 | return NT_STATUS_OK; |
||
1029 | } |
||
1030 | |||
1031 | @@ -315,6 +320,11 @@ bool dcesrv_auth_request(struct dcesrv_c |
||
1032 | return false; |
||
1033 | } |
||
1034 | |||
1035 | + if (pkt->auth_length == 0) { |
||
1036 | + DEBUG(1,("dcesrv_auth_request: unexpected auth_length of 0\n")); |
||
1037 | + return false; |
||
1038 | + } |
||
1039 | + |
||
1040 | status = dcerpc_pull_auth_trailer(pkt, call, |
||
1041 | &pkt->u.request.stub_and_verifier, |
||
1042 | &auth, &auth_length, false); |
||
1043 | --- a/source4/librpc/rpc/dcerpc.c |
||
1044 | +++ b/source4/librpc/rpc/dcerpc.c |
||
1045 | @@ -701,6 +701,14 @@ static NTSTATUS ncacn_pull_request_auth( |
||
1046 | return NT_STATUS_INVALID_LEVEL; |
||
1047 | } |
||
1048 | |||
1049 | + if (pkt->auth_length == 0) { |
||
1050 | + return NT_STATUS_INVALID_NETWORK_RESPONSE; |
||
1051 | + } |
||
1052 | + |
||
1053 | + if (c->security_state.generic_state == NULL) { |
||
1054 | + return NT_STATUS_INTERNAL_ERROR; |
||
1055 | + } |
||
1056 | + |
||
1057 | status = dcerpc_pull_auth_trailer(pkt, mem_ctx, |
||
1058 | &pkt->u.response.stub_and_verifier, |
||
1059 | &auth, &auth_length, false); |
||
1060 | @@ -1074,7 +1082,7 @@ static void dcerpc_bind_recv_handler(str |
||
1061 | } |
||
1062 | |||
1063 | /* the bind_ack might contain a reply set of credentials */ |
||
1064 | - if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) { |
||
1065 | + if (conn->security_state.auth_info && pkt->auth_length) { |
||
1066 | NTSTATUS status; |
||
1067 | uint32_t auth_length; |
||
1068 | status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info, |
||
1069 | @@ -1847,8 +1855,7 @@ static void dcerpc_alter_recv_handler(st |
||
1070 | } |
||
1071 | |||
1072 | /* the alter_resp might contain a reply set of credentials */ |
||
1073 | - if (recv_pipe->conn->security_state.auth_info && |
||
1074 | - pkt->u.alter_resp.auth_info.length) { |
||
1075 | + if (recv_pipe->conn->security_state.auth_info && pkt->auth_length) { |
||
1076 | struct dcecli_connection *conn = recv_pipe->conn; |
||
1077 | NTSTATUS status; |
||
1078 | uint32_t auth_length; |
||
1079 | --- a/source3/librpc/rpc/dcerpc.h |
||
1080 | +++ b/source3/librpc/rpc/dcerpc.h |
||
1081 | @@ -42,6 +42,7 @@ struct pipe_auth_data { |
||
1082 | bool verified_bitmask1; |
||
1083 | |||
1084 | void *auth_ctx; |
||
1085 | + uint32_t auth_context_id; |
||
1086 | |||
1087 | /* Only the client code uses these 3 for now */ |
||
1088 | char *domain; |
||
1089 | @@ -71,10 +72,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_ |
||
1090 | uint32_t auth_context_id, |
||
1091 | const DATA_BLOB *credentials, |
||
1092 | DATA_BLOB *blob); |
||
1093 | -NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, |
||
1094 | - const DATA_BLOB *blob, |
||
1095 | - struct dcerpc_auth *r, |
||
1096 | - bool bigendian); |
||
1097 | NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth, |
||
1098 | size_t header_len, size_t data_left, |
||
1099 | size_t max_xmit_frag, size_t pad_alignment, |
||
1100 | @@ -85,9 +82,8 @@ NTSTATUS dcerpc_add_auth_footer(struct p |
||
1101 | NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, |
||
1102 | struct ncacn_packet *pkt, |
||
1103 | DATA_BLOB *pkt_trailer, |
||
1104 | - size_t header_size, |
||
1105 | - DATA_BLOB *raw_pkt, |
||
1106 | - size_t *pad_len); |
||
1107 | + uint8_t header_size, |
||
1108 | + DATA_BLOB *raw_pkt); |
||
1109 | |||
1110 | /* The following definitions come from librpc/rpc/rpc_common.c */ |
||
1111 | |||
1112 | --- a/source3/rpc_server/srv_pipe.c |
||
1113 | +++ b/source3/rpc_server/srv_pipe.c |
||
1114 | @@ -42,6 +42,7 @@ |
||
1115 | #include "auth.h" |
||
1116 | #include "ntdomain.h" |
||
1117 | #include "rpc_server/srv_pipe.h" |
||
1118 | +#include "../librpc/gen_ndr/ndr_dcerpc.h" |
||
1119 | #include "../librpc/ndr/ndr_dcerpc.h" |
||
1120 | |||
1121 | #undef DBGC_CLASS |
||
1122 | @@ -270,10 +271,14 @@ static bool setup_bind_nak(struct pipes_ |
||
1123 | p->out_data.data_sent_length = 0; |
||
1124 | p->out_data.current_pdu_sent = 0; |
||
1125 | |||
1126 | + set_incoming_fault(p); |
||
1127 | TALLOC_FREE(p->auth.auth_ctx); |
||
1128 | p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE; |
||
1129 | p->auth.auth_type = DCERPC_AUTH_TYPE_NONE; |
||
1130 | p->pipe_bound = False; |
||
1131 | + p->allow_bind = false; |
||
1132 | + p->allow_alter = false; |
||
1133 | + p->allow_auth3 = false; |
||
1134 | |||
1135 | return True; |
||
1136 | } |
||
1137 | @@ -339,16 +344,46 @@ static bool check_bind_req(struct pipes_ |
||
1138 | DEBUG(3,("check_bind_req for %s\n", |
||
1139 | get_pipe_name_from_syntax(talloc_tos(), abstract))); |
||
1140 | |||
1141 | + ok = ndr_syntax_id_equal(transfer, &ndr_transfer_syntax); |
||
1142 | + if (!ok) { |
||
1143 | + DEBUG(1,("check_bind_req unknown transfer syntax for " |
||
1144 | + "%s context_id=%u\n", |
||
1145 | + get_pipe_name_from_syntax(talloc_tos(), abstract), |
||
1146 | + (unsigned)context_id)); |
||
1147 | + return false; |
||
1148 | + } |
||
1149 | + |
||
1150 | + for (context_fns = p->contexts; |
||
1151 | + context_fns != NULL; |
||
1152 | + context_fns = context_fns->next) |
||
1153 | + { |
||
1154 | + if (context_fns->context_id != context_id) { |
||
1155 | + continue; |
||
1156 | + } |
||
1157 | + |
||
1158 | + ok = ndr_syntax_id_equal(&context_fns->syntax, |
||
1159 | + abstract); |
||
1160 | + if (ok) { |
||
1161 | + return true; |
||
1162 | + } |
||
1163 | + |
||
1164 | + DEBUG(1,("check_bind_req: changing abstract syntax for " |
||
1165 | + "%s context_id=%u into %s not supported\n", |
||
1166 | + get_pipe_name_from_syntax(talloc_tos(), &context_fns->syntax), |
||
1167 | + (unsigned)context_id, |
||
1168 | + get_pipe_name_from_syntax(talloc_tos(), abstract))); |
||
1169 | + return false; |
||
1170 | + } |
||
1171 | + |
||
1172 | /* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */ |
||
1173 | - if (rpc_srv_pipe_exists_by_id(abstract) && |
||
1174 | - ndr_syntax_id_equal(transfer, &ndr_transfer_syntax)) { |
||
1175 | - DEBUG(3, ("check_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n", |
||
1176 | - rpc_srv_get_pipe_cli_name(abstract), |
||
1177 | - rpc_srv_get_pipe_srv_name(abstract))); |
||
1178 | - } else { |
||
1179 | + if (!rpc_srv_pipe_exists_by_id(abstract)) { |
||
1180 | return false; |
||
1181 | } |
||
1182 | |||
1183 | + DEBUG(3, ("check_bind_req: %s -> %s rpc service\n", |
||
1184 | + rpc_srv_get_pipe_cli_name(abstract), |
||
1185 | + rpc_srv_get_pipe_srv_name(abstract))); |
||
1186 | + |
||
1187 | context_fns = SMB_MALLOC_P(struct pipe_rpc_fns); |
||
1188 | if (context_fns == NULL) { |
||
1189 | DEBUG(0,("check_bind_req: malloc() failed!\n")); |
||
1190 | @@ -447,6 +482,7 @@ static bool pipe_spnego_auth_bind(struct |
||
1191 | |||
1192 | p->auth.auth_ctx = spnego_ctx; |
||
1193 | p->auth.auth_type = DCERPC_AUTH_TYPE_SPNEGO; |
||
1194 | + p->auth.auth_context_id = auth_info->auth_context_id; |
||
1195 | |||
1196 | DEBUG(10, ("SPNEGO auth started\n")); |
||
1197 | |||
1198 | @@ -557,6 +593,7 @@ static bool pipe_schannel_auth_bind(stru |
||
1199 | /* We're finished with this bind - no more packets. */ |
||
1200 | p->auth.auth_ctx = schannel_auth; |
||
1201 | p->auth.auth_type = DCERPC_AUTH_TYPE_SCHANNEL; |
||
1202 | + p->auth.auth_context_id = auth_info->auth_context_id; |
||
1203 | |||
1204 | p->pipe_bound = True; |
||
1205 | |||
1206 | @@ -601,6 +638,7 @@ static bool pipe_ntlmssp_auth_bind(struc |
||
1207 | |||
1208 | p->auth.auth_ctx = ntlmssp_state; |
||
1209 | p->auth.auth_type = DCERPC_AUTH_TYPE_NTLMSSP; |
||
1210 | + p->auth.auth_context_id = auth_info->auth_context_id; |
||
1211 | |||
1212 | DEBUG(10, (__location__ ": NTLMSSP auth started\n")); |
||
1213 | |||
1214 | @@ -776,6 +814,11 @@ static NTSTATUS pipe_auth_verify_final(s |
||
1215 | void *mech_ctx; |
||
1216 | NTSTATUS status; |
||
1217 | |||
1218 | + if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) { |
||
1219 | + p->pipe_bound = true; |
||
1220 | + return NT_STATUS_OK; |
||
1221 | + } |
||
1222 | + |
||
1223 | switch (p->auth.auth_type) { |
||
1224 | case DCERPC_AUTH_TYPE_NTLMSSP: |
||
1225 | ntlmssp_ctx = talloc_get_type_abort(p->auth.auth_ctx, |
||
1226 | @@ -867,16 +910,38 @@ static bool api_pipe_bind_req(struct pip |
||
1227 | DATA_BLOB auth_resp = data_blob_null; |
||
1228 | DATA_BLOB auth_blob = data_blob_null; |
||
1229 | |||
1230 | - /* No rebinds on a bound pipe - use alter context. */ |
||
1231 | - if (p->pipe_bound) { |
||
1232 | - DEBUG(2,("api_pipe_bind_req: rejecting bind request on bound " |
||
1233 | - "pipe %s.\n", |
||
1234 | - get_pipe_name_from_syntax(talloc_tos(), &p->syntax))); |
||
1235 | + if (!p->allow_bind) { |
||
1236 | + DEBUG(2,("Pipe not in allow bind state\n")); |
||
1237 | return setup_bind_nak(p, pkt); |
||
1238 | } |
||
1239 | + p->allow_bind = false; |
||
1240 | + |
||
1241 | + status = dcerpc_verify_ncacn_packet_header(pkt, |
||
1242 | + DCERPC_PKT_BIND, |
||
1243 | + pkt->u.bind.auth_info.length, |
||
1244 | + 0, /* required flags */ |
||
1245 | + DCERPC_PFC_FLAG_FIRST | |
||
1246 | + DCERPC_PFC_FLAG_LAST | |
||
1247 | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | |
||
1248 | + 0x08 | /* this is not defined, but should be ignored */ |
||
1249 | + DCERPC_PFC_FLAG_CONC_MPX | |
||
1250 | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | |
||
1251 | + DCERPC_PFC_FLAG_MAYBE | |
||
1252 | + DCERPC_PFC_FLAG_OBJECT_UUID); |
||
1253 | + if (!NT_STATUS_IS_OK(status)) { |
||
1254 | + DEBUG(1, ("api_pipe_bind_req: invalid pdu: %s\n", |
||
1255 | + nt_errstr(status))); |
||
1256 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
1257 | + goto err_exit; |
||
1258 | + } |
||
1259 | |||
1260 | if (pkt->u.bind.num_contexts == 0) { |
||
1261 | - DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n")); |
||
1262 | + DEBUG(1, ("api_pipe_bind_req: no rpc contexts around\n")); |
||
1263 | + goto err_exit; |
||
1264 | + } |
||
1265 | + |
||
1266 | + if (pkt->u.bind.ctx_list[0].num_transfer_syntaxes == 0) { |
||
1267 | + DEBUG(1, ("api_pipe_bind_req: no transfer syntaxes around\n")); |
||
1268 | goto err_exit; |
||
1269 | } |
||
1270 | |||
1271 | @@ -960,25 +1025,12 @@ static bool api_pipe_bind_req(struct pip |
||
1272 | * Check if this is an authenticated bind request. |
||
1273 | */ |
||
1274 | if (pkt->auth_length) { |
||
1275 | - /* Quick length check. Won't catch a bad auth footer, |
||
1276 | - * prevents overrun. */ |
||
1277 | - |
||
1278 | - if (pkt->frag_length < RPC_HEADER_LEN + |
||
1279 | - DCERPC_AUTH_TRAILER_LENGTH + |
||
1280 | - pkt->auth_length) { |
||
1281 | - DEBUG(0,("api_pipe_bind_req: auth_len (%u) " |
||
1282 | - "too long for fragment %u.\n", |
||
1283 | - (unsigned int)pkt->auth_length, |
||
1284 | - (unsigned int)pkt->frag_length)); |
||
1285 | - goto err_exit; |
||
1286 | - } |
||
1287 | - |
||
1288 | /* |
||
1289 | * Decode the authentication verifier. |
||
1290 | */ |
||
1291 | - status = dcerpc_pull_dcerpc_auth(pkt, |
||
1292 | - &pkt->u.bind.auth_info, |
||
1293 | - &auth_info, p->endian); |
||
1294 | + status = dcerpc_pull_auth_trailer(pkt, pkt, |
||
1295 | + &pkt->u.bind.auth_info, |
||
1296 | + &auth_info, NULL, true); |
||
1297 | if (!NT_STATUS_IS_OK(status)) { |
||
1298 | DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n")); |
||
1299 | goto err_exit; |
||
1300 | @@ -1072,6 +1124,7 @@ static bool api_pipe_bind_req(struct pip |
||
1301 | p->pipe_bound = True; |
||
1302 | /* The session key was initialized from the SMB |
||
1303 | * session in make_internal_rpc_pipe_p */ |
||
1304 | + p->auth.auth_context_id = 0; |
||
1305 | } |
||
1306 | |||
1307 | ZERO_STRUCT(u.bind_ack); |
||
1308 | @@ -1113,15 +1166,15 @@ static bool api_pipe_bind_req(struct pip |
||
1309 | if (!NT_STATUS_IS_OK(status)) { |
||
1310 | DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n", |
||
1311 | nt_errstr(status))); |
||
1312 | + goto err_exit; |
||
1313 | } |
||
1314 | |||
1315 | if (auth_resp.length) { |
||
1316 | - |
||
1317 | status = dcerpc_push_dcerpc_auth(pkt, |
||
1318 | auth_type, |
||
1319 | auth_info.auth_level, |
||
1320 | - 0, |
||
1321 | - 1, /* auth_context_id */ |
||
1322 | + 0, /* pad_len */ |
||
1323 | + p->auth.auth_context_id, |
||
1324 | &auth_resp, |
||
1325 | &auth_blob); |
||
1326 | if (!NT_STATUS_IS_OK(status)) { |
||
1327 | @@ -1152,6 +1205,22 @@ static bool api_pipe_bind_req(struct pip |
||
1328 | p->out_data.current_pdu_sent = 0; |
||
1329 | |||
1330 | TALLOC_FREE(auth_blob.data); |
||
1331 | + |
||
1332 | + if (bind_ack_ctx.result == 0) { |
||
1333 | + p->allow_alter = true; |
||
1334 | + p->allow_auth3 = true; |
||
1335 | + if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) { |
||
1336 | + status = pipe_auth_verify_final(p); |
||
1337 | + if (!NT_STATUS_IS_OK(status)) { |
||
1338 | + DEBUG(0, ("pipe_auth_verify_final failed: %s\n", |
||
1339 | + nt_errstr(status))); |
||
1340 | + goto err_exit; |
||
1341 | + } |
||
1342 | + } |
||
1343 | + } else { |
||
1344 | + goto err_exit; |
||
1345 | + } |
||
1346 | + |
||
1347 | return True; |
||
1348 | |||
1349 | err_exit: |
||
1350 | @@ -1176,18 +1245,39 @@ bool api_pipe_bind_auth3(struct pipes_st |
||
1351 | |||
1352 | DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__)); |
||
1353 | |||
1354 | - if (pkt->auth_length == 0) { |
||
1355 | - DEBUG(0, ("No auth field sent for bind request!\n")); |
||
1356 | + if (!p->allow_auth3) { |
||
1357 | + DEBUG(1, ("Pipe not in allow auth3 state.\n")); |
||
1358 | goto err; |
||
1359 | } |
||
1360 | |||
1361 | - /* Ensure there's enough data for an authenticated request. */ |
||
1362 | - if (pkt->frag_length < RPC_HEADER_LEN |
||
1363 | - + DCERPC_AUTH_TRAILER_LENGTH |
||
1364 | - + pkt->auth_length) { |
||
1365 | - DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len " |
||
1366 | - "%u is too large.\n", |
||
1367 | - (unsigned int)pkt->auth_length)); |
||
1368 | + status = dcerpc_verify_ncacn_packet_header(pkt, |
||
1369 | + DCERPC_PKT_AUTH3, |
||
1370 | + pkt->u.auth3.auth_info.length, |
||
1371 | + 0, /* required flags */ |
||
1372 | + DCERPC_PFC_FLAG_FIRST | |
||
1373 | + DCERPC_PFC_FLAG_LAST | |
||
1374 | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | |
||
1375 | + 0x08 | /* this is not defined, but should be ignored */ |
||
1376 | + DCERPC_PFC_FLAG_CONC_MPX | |
||
1377 | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | |
||
1378 | + DCERPC_PFC_FLAG_MAYBE | |
||
1379 | + DCERPC_PFC_FLAG_OBJECT_UUID); |
||
1380 | + if (!NT_STATUS_IS_OK(status)) { |
||
1381 | + DEBUG(1, ("api_pipe_bind_auth3: invalid pdu: %s\n", |
||
1382 | + nt_errstr(status))); |
||
1383 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
1384 | + goto err; |
||
1385 | + } |
||
1386 | + |
||
1387 | + /* We can only finish if the pipe is unbound for now */ |
||
1388 | + if (p->pipe_bound) { |
||
1389 | + DEBUG(0, (__location__ ": Pipe already bound, " |
||
1390 | + "AUTH3 not supported!\n")); |
||
1391 | + goto err; |
||
1392 | + } |
||
1393 | + |
||
1394 | + if (pkt->auth_length == 0) { |
||
1395 | + DEBUG(1, ("No auth field sent for auth3 request!\n")); |
||
1396 | goto err; |
||
1397 | } |
||
1398 | |||
1399 | @@ -1195,9 +1285,9 @@ bool api_pipe_bind_auth3(struct pipes_st |
||
1400 | * Decode the authentication verifier response. |
||
1401 | */ |
||
1402 | |||
1403 | - status = dcerpc_pull_dcerpc_auth(pkt, |
||
1404 | - &pkt->u.auth3.auth_info, |
||
1405 | - &auth_info, p->endian); |
||
1406 | + status = dcerpc_pull_auth_trailer(pkt, pkt, |
||
1407 | + &pkt->u.auth3.auth_info, |
||
1408 | + &auth_info, NULL, true); |
||
1409 | if (!NT_STATUS_IS_OK(status)) { |
||
1410 | DEBUG(0, ("Failed to unmarshall dcerpc_auth.\n")); |
||
1411 | goto err; |
||
1412 | @@ -1215,6 +1305,21 @@ bool api_pipe_bind_auth3(struct pipes_st |
||
1413 | goto err; |
||
1414 | } |
||
1415 | |||
1416 | + if (auth_info.auth_level != p->auth.auth_level) { |
||
1417 | + DEBUG(1, ("Auth level mismatch! Client sent %d, " |
||
1418 | + "but auth was started as level %d!\n", |
||
1419 | + auth_info.auth_level, p->auth.auth_level)); |
||
1420 | + goto err; |
||
1421 | + } |
||
1422 | + |
||
1423 | + if (auth_info.auth_context_id != p->auth.auth_context_id) { |
||
1424 | + DEBUG(0, ("Auth context id mismatch! Client sent %u, " |
||
1425 | + "but auth was started as level %u!\n", |
||
1426 | + (unsigned)auth_info.auth_context_id, |
||
1427 | + (unsigned)p->auth.auth_context_id)); |
||
1428 | + goto err; |
||
1429 | + } |
||
1430 | + |
||
1431 | switch (auth_info.auth_type) { |
||
1432 | case DCERPC_AUTH_TYPE_NTLMSSP: |
||
1433 | ntlmssp_ctx = talloc_get_type_abort(p->auth.auth_ctx, |
||
1434 | @@ -1267,6 +1372,10 @@ bool api_pipe_bind_auth3(struct pipes_st |
||
1435 | return true; |
||
1436 | |||
1437 | err: |
||
1438 | + p->pipe_bound = false; |
||
1439 | + p->allow_bind = false; |
||
1440 | + p->allow_alter = false; |
||
1441 | + p->allow_auth3 = false; |
||
1442 | |||
1443 | TALLOC_FREE(p->auth.auth_ctx); |
||
1444 | return false; |
||
1445 | @@ -1284,7 +1393,7 @@ static bool api_pipe_alter_context(struc |
||
1446 | uint16 assoc_gid; |
||
1447 | NTSTATUS status; |
||
1448 | union dcerpc_payload u; |
||
1449 | - struct dcerpc_ack_ctx bind_ack_ctx; |
||
1450 | + struct dcerpc_ack_ctx alter_ack_ctx; |
||
1451 | DATA_BLOB auth_resp = data_blob_null; |
||
1452 | DATA_BLOB auth_blob = data_blob_null; |
||
1453 | int pad_len = 0; |
||
1454 | @@ -1294,8 +1403,42 @@ static bool api_pipe_alter_context(struc |
||
1455 | |||
1456 | DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__)); |
||
1457 | |||
1458 | - if (pkt->u.bind.assoc_group_id != 0) { |
||
1459 | - assoc_gid = pkt->u.bind.assoc_group_id; |
||
1460 | + if (!p->allow_alter) { |
||
1461 | + DEBUG(1, ("Pipe not in allow alter state.\n")); |
||
1462 | + goto err_exit; |
||
1463 | + } |
||
1464 | + |
||
1465 | + status = dcerpc_verify_ncacn_packet_header(pkt, |
||
1466 | + DCERPC_PKT_ALTER, |
||
1467 | + pkt->u.alter.auth_info.length, |
||
1468 | + 0, /* required flags */ |
||
1469 | + DCERPC_PFC_FLAG_FIRST | |
||
1470 | + DCERPC_PFC_FLAG_LAST | |
||
1471 | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | |
||
1472 | + 0x08 | /* this is not defined, but should be ignored */ |
||
1473 | + DCERPC_PFC_FLAG_CONC_MPX | |
||
1474 | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | |
||
1475 | + DCERPC_PFC_FLAG_MAYBE | |
||
1476 | + DCERPC_PFC_FLAG_OBJECT_UUID); |
||
1477 | + if (!NT_STATUS_IS_OK(status)) { |
||
1478 | + DEBUG(1, ("api_pipe_alter_context: invalid pdu: %s\n", |
||
1479 | + nt_errstr(status))); |
||
1480 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
1481 | + goto err_exit; |
||
1482 | + } |
||
1483 | + |
||
1484 | + if (pkt->u.alter.num_contexts == 0) { |
||
1485 | + DEBUG(1, ("api_pipe_alter_context: no rpc contexts around\n")); |
||
1486 | + goto err_exit; |
||
1487 | + } |
||
1488 | + |
||
1489 | + if (pkt->u.alter.ctx_list[0].num_transfer_syntaxes == 0) { |
||
1490 | + DEBUG(1, ("api_pipe_alter_context: no transfer syntaxes around\n")); |
||
1491 | + goto err_exit; |
||
1492 | + } |
||
1493 | + |
||
1494 | + if (pkt->u.alter.assoc_group_id != 0) { |
||
1495 | + assoc_gid = pkt->u.alter.assoc_group_id; |
||
1496 | } else { |
||
1497 | assoc_gid = 0x53f0; |
||
1498 | } |
||
1499 | @@ -1305,59 +1448,45 @@ static bool api_pipe_alter_context(struc |
||
1500 | */ |
||
1501 | |||
1502 | /* If the requested abstract synt uuid doesn't match our client pipe, |
||
1503 | - reject the bind_ack & set the transfer interface synt to all 0's, |
||
1504 | + reject the alter_ack & set the transfer interface synt to all 0's, |
||
1505 | ver 0 (observed when NT5 attempts to bind to abstract interfaces |
||
1506 | unknown to NT4) |
||
1507 | Needed when adding entries to a DACL from NT5 - SK */ |
||
1508 | |||
1509 | if (check_bind_req(p, |
||
1510 | - &pkt->u.bind.ctx_list[0].abstract_syntax, |
||
1511 | - &pkt->u.bind.ctx_list[0].transfer_syntaxes[0], |
||
1512 | - pkt->u.bind.ctx_list[0].context_id)) { |
||
1513 | - |
||
1514 | - bind_ack_ctx.result = 0; |
||
1515 | - bind_ack_ctx.reason = 0; |
||
1516 | - bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0]; |
||
1517 | + &pkt->u.alter.ctx_list[0].abstract_syntax, |
||
1518 | + &pkt->u.alter.ctx_list[0].transfer_syntaxes[0], |
||
1519 | + pkt->u.alter.ctx_list[0].context_id)) { |
||
1520 | + |
||
1521 | + alter_ack_ctx.result = 0; |
||
1522 | + alter_ack_ctx.reason = 0; |
||
1523 | + alter_ack_ctx.syntax = pkt->u.alter.ctx_list[0].transfer_syntaxes[0]; |
||
1524 | } else { |
||
1525 | - p->pipe_bound = False; |
||
1526 | /* Rejection reason: abstract syntax not supported */ |
||
1527 | - bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT; |
||
1528 | - bind_ack_ctx.reason = DCERPC_BIND_REASON_ASYNTAX; |
||
1529 | - bind_ack_ctx.syntax = null_ndr_syntax_id; |
||
1530 | + alter_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT; |
||
1531 | + alter_ack_ctx.reason = DCERPC_BIND_REASON_ASYNTAX; |
||
1532 | + alter_ack_ctx.syntax = null_ndr_syntax_id; |
||
1533 | } |
||
1534 | |||
1535 | /* |
||
1536 | * Check if this is an authenticated alter context request. |
||
1537 | */ |
||
1538 | if (pkt->auth_length) { |
||
1539 | - /* Quick length check. Won't catch a bad auth footer, |
||
1540 | - * prevents overrun. */ |
||
1541 | - |
||
1542 | - if (pkt->frag_length < RPC_HEADER_LEN + |
||
1543 | - DCERPC_AUTH_TRAILER_LENGTH + |
||
1544 | - pkt->auth_length) { |
||
1545 | - DEBUG(0,("api_pipe_alter_context: auth_len (%u) " |
||
1546 | - "too long for fragment %u.\n", |
||
1547 | - (unsigned int)pkt->auth_length, |
||
1548 | - (unsigned int)pkt->frag_length )); |
||
1549 | + /* We can only finish if the pipe is unbound for now */ |
||
1550 | + if (p->pipe_bound) { |
||
1551 | + DEBUG(0, (__location__ ": Pipe already bound, " |
||
1552 | + "Altering Context not yet supported!\n")); |
||
1553 | goto err_exit; |
||
1554 | } |
||
1555 | |||
1556 | - status = dcerpc_pull_dcerpc_auth(pkt, |
||
1557 | - &pkt->u.bind.auth_info, |
||
1558 | - &auth_info, p->endian); |
||
1559 | + status = dcerpc_pull_auth_trailer(pkt, pkt, |
||
1560 | + &pkt->u.alter.auth_info, |
||
1561 | + &auth_info, NULL, true); |
||
1562 | if (!NT_STATUS_IS_OK(status)) { |
||
1563 | DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n")); |
||
1564 | goto err_exit; |
||
1565 | } |
||
1566 | |||
1567 | - /* We can only finish if the pipe is unbound for now */ |
||
1568 | - if (p->pipe_bound) { |
||
1569 | - DEBUG(0, (__location__ ": Pipe already bound, " |
||
1570 | - "Altering Context not yet supported!\n")); |
||
1571 | - goto err_exit; |
||
1572 | - } |
||
1573 | - |
||
1574 | if (auth_info.auth_type != p->auth.auth_type) { |
||
1575 | DEBUG(0, ("Auth type mismatch! Client sent %d, " |
||
1576 | "but auth was started as type %d!\n", |
||
1577 | @@ -1365,6 +1494,20 @@ static bool api_pipe_alter_context(struc |
||
1578 | goto err_exit; |
||
1579 | } |
||
1580 | |||
1581 | + if (auth_info.auth_level != p->auth.auth_level) { |
||
1582 | + DEBUG(0, ("Auth level mismatch! Client sent %d, " |
||
1583 | + "but auth was started as level %d!\n", |
||
1584 | + auth_info.auth_level, p->auth.auth_level)); |
||
1585 | + goto err_exit; |
||
1586 | + } |
||
1587 | + |
||
1588 | + if (auth_info.auth_context_id != p->auth.auth_context_id) { |
||
1589 | + DEBUG(0, ("Auth context id mismatch! Client sent %u, " |
||
1590 | + "but auth was started as level %u!\n", |
||
1591 | + (unsigned)auth_info.auth_context_id, |
||
1592 | + (unsigned)p->auth.auth_context_id)); |
||
1593 | + goto err_exit; |
||
1594 | + } |
||
1595 | |||
1596 | switch (auth_info.auth_type) { |
||
1597 | case DCERPC_AUTH_TYPE_SPNEGO: |
||
1598 | @@ -1431,7 +1574,7 @@ static bool api_pipe_alter_context(struc |
||
1599 | u.alter_resp.secondary_address_size = 1; |
||
1600 | |||
1601 | u.alter_resp.num_results = 1; |
||
1602 | - u.alter_resp.ctx_list = &bind_ack_ctx; |
||
1603 | + u.alter_resp.ctx_list = &alter_ack_ctx; |
||
1604 | |||
1605 | /* NOTE: We leave the auth_info empty so we can calculate the padding |
||
1606 | * later and then append the auth_info --simo */ |
||
1607 | @@ -1451,8 +1594,9 @@ static bool api_pipe_alter_context(struc |
||
1608 | &u, |
||
1609 | &p->out_data.frag); |
||
1610 | if (!NT_STATUS_IS_OK(status)) { |
||
1611 | - DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n", |
||
1612 | + DEBUG(0, ("Failed to marshall alter_resp packet. (%s)\n", |
||
1613 | nt_errstr(status))); |
||
1614 | + goto err_exit; |
||
1615 | } |
||
1616 | |||
1617 | if (auth_resp.length) { |
||
1618 | @@ -1469,7 +1613,7 @@ static bool api_pipe_alter_context(struc |
||
1619 | auth_info.auth_type, |
||
1620 | auth_info.auth_level, |
||
1621 | pad_len, |
||
1622 | - 1, /* auth_context_id */ |
||
1623 | + p->auth.auth_context_id, |
||
1624 | &auth_resp, |
||
1625 | &auth_blob); |
||
1626 | if (!NT_STATUS_IS_OK(status)) { |
||
1627 | @@ -1618,6 +1762,7 @@ static bool api_pipe_request(struct pipe |
||
1628 | |||
1629 | if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) { |
||
1630 | DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n")); |
||
1631 | + set_incoming_fault(p); |
||
1632 | setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED)); |
||
1633 | data_blob_free(&p->out_data.rdata); |
||
1634 | TALLOC_FREE(frame); |
||
1635 | @@ -1756,7 +1901,11 @@ void set_incoming_fault(struct pipes_str |
||
1636 | data_blob_free(&p->in_data.data); |
||
1637 | p->in_data.pdu_needed_len = 0; |
||
1638 | p->in_data.pdu.length = 0; |
||
1639 | - p->fault_state = DCERPC_FAULT_CANT_PERFORM; |
||
1640 | + p->fault_state = DCERPC_NCA_S_PROTO_ERROR; |
||
1641 | + |
||
1642 | + p->allow_alter = false; |
||
1643 | + p->allow_auth3 = false; |
||
1644 | + p->pipe_bound = false; |
||
1645 | |||
1646 | DEBUG(10, ("Setting fault state\n")); |
||
1647 | } |
||
1648 | @@ -1767,7 +1916,6 @@ static NTSTATUS dcesrv_auth_request(stru |
||
1649 | { |
||
1650 | NTSTATUS status; |
||
1651 | size_t hdr_size = DCERPC_REQUEST_LENGTH; |
||
1652 | - size_t pad_len; |
||
1653 | |||
1654 | DEBUG(10, ("Checking request auth.\n")); |
||
1655 | |||
1656 | @@ -1778,25 +1926,11 @@ static NTSTATUS dcesrv_auth_request(stru |
||
1657 | /* in case of sealing this function will unseal the data in place */ |
||
1658 | status = dcerpc_check_auth(auth, pkt, |
||
1659 | &pkt->u.request.stub_and_verifier, |
||
1660 | - hdr_size, raw_pkt, |
||
1661 | - &pad_len); |
||
1662 | + hdr_size, raw_pkt); |
||
1663 | if (!NT_STATUS_IS_OK(status)) { |
||
1664 | return status; |
||
1665 | } |
||
1666 | |||
1667 | - |
||
1668 | - /* remove padding and auth trailer, |
||
1669 | - * this way the caller will get just the data */ |
||
1670 | - if (pkt->auth_length) { |
||
1671 | - size_t trail_len = pad_len |
||
1672 | - + DCERPC_AUTH_TRAILER_LENGTH |
||
1673 | - + pkt->auth_length; |
||
1674 | - if (pkt->u.request.stub_and_verifier.length < trail_len) { |
||
1675 | - return NT_STATUS_INFO_LENGTH_MISMATCH; |
||
1676 | - } |
||
1677 | - pkt->u.request.stub_and_verifier.length -= trail_len; |
||
1678 | - } |
||
1679 | - |
||
1680 | return NT_STATUS_OK; |
||
1681 | } |
||
1682 | |||
1683 | @@ -1816,6 +1950,29 @@ static bool process_request_pdu(struct p |
||
1684 | return False; |
||
1685 | } |
||
1686 | |||
1687 | + /* |
||
1688 | + * We don't ignore DCERPC_PFC_FLAG_PENDING_CANCEL. |
||
1689 | + * TODO: we can reject it with DCERPC_FAULT_NO_CALL_ACTIVE later. |
||
1690 | + */ |
||
1691 | + status = dcerpc_verify_ncacn_packet_header(pkt, |
||
1692 | + DCERPC_PKT_REQUEST, |
||
1693 | + pkt->u.request.stub_and_verifier.length, |
||
1694 | + 0, /* required_flags */ |
||
1695 | + DCERPC_PFC_FLAG_FIRST | |
||
1696 | + DCERPC_PFC_FLAG_LAST | |
||
1697 | + 0x08 | /* this is not defined, but should be ignored */ |
||
1698 | + DCERPC_PFC_FLAG_CONC_MPX | |
||
1699 | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | |
||
1700 | + DCERPC_PFC_FLAG_MAYBE | |
||
1701 | + DCERPC_PFC_FLAG_OBJECT_UUID); |
||
1702 | + if (!NT_STATUS_IS_OK(status)) { |
||
1703 | + DEBUG(1, ("process_request_pdu: invalid pdu: %s\n", |
||
1704 | + nt_errstr(status))); |
||
1705 | + NDR_PRINT_DEBUG(ncacn_packet, pkt); |
||
1706 | + set_incoming_fault(p); |
||
1707 | + return false; |
||
1708 | + } |
||
1709 | + |
||
1710 | /* Store the opnum */ |
||
1711 | p->opnum = pkt->u.request.opnum; |
||
1712 | |||
1713 | @@ -2065,7 +2222,7 @@ done: |
||
1714 | "pipe %s\n", get_pipe_name_from_syntax(talloc_tos(), |
||
1715 | &p->syntax))); |
||
1716 | set_incoming_fault(p); |
||
1717 | - setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR)); |
||
1718 | + setup_fault_pdu(p, NT_STATUS(DCERPC_NCA_S_PROTO_ERROR)); |
||
1719 | TALLOC_FREE(pkt); |
||
1720 | } else { |
||
1721 | /* |
||
1722 | --- a/source3/include/ntdomain.h |
||
1723 | +++ b/source3/include/ntdomain.h |
||
1724 | @@ -135,6 +135,13 @@ struct pipes_struct { |
||
1725 | bool pipe_bound; |
||
1726 | |||
1727 | /* |
||
1728 | + * States we can be in. |
||
1729 | + */ |
||
1730 | + bool allow_alter; |
||
1731 | + bool allow_bind; |
||
1732 | + bool allow_auth3; |
||
1733 | + |
||
1734 | + /* |
||
1735 | * Set the DCERPC_FAULT to return. |
||
1736 | */ |
||
1737 | |||
1738 | --- a/source3/rpc_server/rpc_ncacn_np.c |
||
1739 | +++ b/source3/rpc_server/rpc_ncacn_np.c |
||
1740 | @@ -171,6 +171,7 @@ struct pipes_struct *make_internal_rpc_p |
||
1741 | |||
1742 | p->syntax = *syntax; |
||
1743 | p->transport = NCALRPC; |
||
1744 | + p->allow_bind = true; |
||
1745 | |||
1746 | DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n", |
||
1747 | get_pipe_name_from_syntax(talloc_tos(), syntax), pipes_open)); |
||
1748 | @@ -780,6 +781,7 @@ static NTSTATUS rpc_pipe_open_external(T |
||
1749 | } |
||
1750 | result->auth->auth_type = DCERPC_AUTH_TYPE_NONE; |
||
1751 | result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE; |
||
1752 | + result->auth->auth_context_id = 0; |
||
1753 | |||
1754 | status = rpccli_anon_bind_data(result, &auth); |
||
1755 | if (!NT_STATUS_IS_OK(status)) { |
||
1756 | --- a/source3/rpc_server/rpc_server.c |
||
1757 | +++ b/source3/rpc_server/rpc_server.c |
||
1758 | @@ -102,6 +102,7 @@ static int make_server_pipes_struct(TALL |
||
1759 | p->syntax = id; |
||
1760 | p->transport = transport; |
||
1761 | p->ncalrpc_as_system = ncalrpc_as_system; |
||
1762 | + p->allow_bind = true; |
||
1763 | |||
1764 | p->mem_ctx = talloc_named(p, 0, "pipe %s %p", pipe_name, p); |
||
1765 | if (!p->mem_ctx) { |
||
1766 | @@ -663,6 +664,12 @@ static void named_pipe_packet_done(struc |
||
1767 | goto fail; |
||
1768 | } |
||
1769 | |||
1770 | + if (npc->p->fault_state != 0) { |
||
1771 | + DEBUG(2, ("Disconnect after fault\n")); |
||
1772 | + sys_errno = EINVAL; |
||
1773 | + goto fail; |
||
1774 | + } |
||
1775 | + |
||
1776 | /* clear out any data that may have been left around */ |
||
1777 | npc->count = 0; |
||
1778 | TALLOC_FREE(npc->iov); |
||
1779 | @@ -1391,6 +1398,12 @@ static void dcerpc_ncacn_packet_done(str |
||
1780 | goto fail; |
||
1781 | } |
||
1782 | |||
1783 | + if (ncacn_conn->p->fault_state != 0) { |
||
1784 | + DEBUG(2, ("Disconnect after fault\n")); |
||
1785 | + sys_errno = EINVAL; |
||
1786 | + goto fail; |
||
1787 | + } |
||
1788 | + |
||
1789 | /* clear out any data that may have been left around */ |
||
1790 | ncacn_conn->count = 0; |
||
1791 | TALLOC_FREE(ncacn_conn->iov); |