lib/poll_funcs: free contexts in poll_funcs_state_destructor()
[Samba.git] / source3 / librpc / rpc / dcerpc_helpers.c
blobaab43a1abd4c5505f5eb8c9155ac9e392c761e95
1 /*
2 * DCERPC Helper routines
3 * Günther Deschner <gd@samba.org> 2010.
4 * Simo Sorce <idra@samba.org> 2010.
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.
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.
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/>.
21 #include "includes.h"
22 #include "librpc/rpc/dcerpc.h"
23 #include "librpc/gen_ndr/ndr_dcerpc.h"
24 #include "librpc/crypto/gse.h"
25 #include "auth/gensec/gensec.h"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_RPC_PARSE
30 /**
31 * @brief NDR Encodes a ncacn_packet
33 * @param mem_ctx The memory context the blob will be allocated on
34 * @param ptype The DCERPC packet type
35 * @param pfc_flags The DCERPC PFC Falgs
36 * @param auth_length The length of the trailing auth blob
37 * @param call_id The call ID
38 * @param u The payload of the packet
39 * @param blob [out] The encoded blob if successful
41 * @return an NTSTATUS error code
43 NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx,
44 enum dcerpc_pkt_type ptype,
45 uint8_t pfc_flags,
46 uint16_t auth_length,
47 uint32_t call_id,
48 union dcerpc_payload *u,
49 DATA_BLOB *blob)
51 struct ncacn_packet r;
52 enum ndr_err_code ndr_err;
54 r.rpc_vers = 5;
55 r.rpc_vers_minor = 0;
56 r.ptype = ptype;
57 r.pfc_flags = pfc_flags;
58 r.drep[0] = DCERPC_DREP_LE;
59 r.drep[1] = 0;
60 r.drep[2] = 0;
61 r.drep[3] = 0;
62 r.auth_length = auth_length;
63 r.call_id = call_id;
64 r.u = *u;
66 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
67 (ndr_push_flags_fn_t)ndr_push_ncacn_packet);
68 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
69 return ndr_map_error2ntstatus(ndr_err);
72 dcerpc_set_frag_length(blob, blob->length);
75 if (DEBUGLEVEL >= 10) {
76 /* set frag len for print function */
77 r.frag_length = blob->length;
78 NDR_PRINT_DEBUG(ncacn_packet, &r);
81 return NT_STATUS_OK;
84 /**
85 * @brief Decodes a ncacn_packet
87 * @param mem_ctx The memory context on which to allocate the packet
88 * elements
89 * @param blob The blob of data to decode
90 * @param r An empty ncacn_packet, must not be NULL
91 * @param bigendian Whether the packet is bignedian encoded
93 * @return a NTSTATUS error code
95 NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
96 const DATA_BLOB *blob,
97 struct ncacn_packet *r,
98 bool bigendian)
100 enum ndr_err_code ndr_err;
101 struct ndr_pull *ndr;
103 ndr = ndr_pull_init_blob(blob, mem_ctx);
104 if (!ndr) {
105 return NT_STATUS_NO_MEMORY;
107 if (bigendian) {
108 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
111 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
112 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
115 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, r);
117 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
118 talloc_free(ndr);
119 return ndr_map_error2ntstatus(ndr_err);
121 talloc_free(ndr);
123 if (DEBUGLEVEL >= 10) {
124 NDR_PRINT_DEBUG(ncacn_packet, r);
127 if (r->frag_length != blob->length) {
128 return NT_STATUS_RPC_PROTOCOL_ERROR;
131 return NT_STATUS_OK;
135 * @brief NDR Encodes a dcerpc_auth structure
137 * @param mem_ctx The memory context the blob will be allocated on
138 * @param auth_type The DCERPC Authentication Type
139 * @param auth_level The DCERPC Authentication Level
140 * @param auth_pad_length The padding added to the packet this blob will be
141 * appended to.
142 * @param auth_context_id The context id
143 * @param credentials The authentication credentials blob (signature)
144 * @param blob [out] The encoded blob if successful
146 * @return a NTSTATUS error code
148 NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx,
149 enum dcerpc_AuthType auth_type,
150 enum dcerpc_AuthLevel auth_level,
151 uint8_t auth_pad_length,
152 uint32_t auth_context_id,
153 const DATA_BLOB *credentials,
154 DATA_BLOB *blob)
156 struct dcerpc_auth r;
157 enum ndr_err_code ndr_err;
159 r.auth_type = auth_type;
160 r.auth_level = auth_level;
161 r.auth_pad_length = auth_pad_length;
162 r.auth_reserved = 0;
163 r.auth_context_id = auth_context_id;
164 r.credentials = *credentials;
166 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
167 (ndr_push_flags_fn_t)ndr_push_dcerpc_auth);
168 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
169 return ndr_map_error2ntstatus(ndr_err);
172 if (DEBUGLEVEL >= 10) {
173 NDR_PRINT_DEBUG(dcerpc_auth, &r);
176 return NT_STATUS_OK;
180 * @brief Calculate how much data we can in a packet, including calculating
181 * auth token and pad lengths.
183 * @param auth The pipe_auth_data structure for this pipe.
184 * @param header_len The length of the packet header
185 * @param data_left The data left in the send buffer
186 * @param max_xmit_frag The max fragment size.
187 * @param data_to_send [out] The max data we will send in the pdu
188 * @param frag_len [out] The total length of the fragment
189 * @param auth_len [out] The length of the auth trailer
190 * @param pad_len [out] The padding to be applied
192 * @return A NT Error status code.
194 NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
195 size_t header_len, size_t data_left,
196 size_t max_xmit_frag,
197 size_t *data_to_send, size_t *frag_len,
198 size_t *auth_len, size_t *pad_len)
200 size_t max_len;
201 size_t mod_len;
202 struct gensec_security *gensec_security;
204 /* no auth token cases first */
205 switch (auth->auth_level) {
206 case DCERPC_AUTH_LEVEL_NONE:
207 case DCERPC_AUTH_LEVEL_CONNECT:
208 case DCERPC_AUTH_LEVEL_PACKET:
209 max_len = max_xmit_frag - header_len;
210 *data_to_send = MIN(max_len, data_left);
211 *pad_len = 0;
212 *auth_len = 0;
213 *frag_len = header_len + *data_to_send;
214 return NT_STATUS_OK;
216 case DCERPC_AUTH_LEVEL_PRIVACY:
217 break;
219 case DCERPC_AUTH_LEVEL_INTEGRITY:
220 break;
222 default:
223 return NT_STATUS_INVALID_PARAMETER;
227 /* Sign/seal case, calculate auth and pad lengths */
229 max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH;
231 /* Treat the same for all authenticated rpc requests. */
232 switch (auth->auth_type) {
233 case DCERPC_AUTH_TYPE_SPNEGO:
234 case DCERPC_AUTH_TYPE_NTLMSSP:
235 case DCERPC_AUTH_TYPE_KRB5:
236 case DCERPC_AUTH_TYPE_SCHANNEL:
237 gensec_security = auth->auth_ctx;
238 mod_len = (max_len % DCERPC_AUTH_PAD_ALIGNMENT);
239 *auth_len = gensec_sig_size(gensec_security, max_len - mod_len);
240 if (*auth_len == 0) {
241 return NT_STATUS_INTERNAL_ERROR;
243 break;
244 default:
245 return NT_STATUS_INVALID_PARAMETER;
248 max_len -= *auth_len;
249 mod_len = (max_len % DCERPC_AUTH_PAD_ALIGNMENT);
250 max_len -= mod_len;
252 *data_to_send = MIN(max_len, data_left);
254 *pad_len = DCERPC_AUTH_PAD_LENGTH(*data_to_send);
256 *frag_len = header_len + *data_to_send + *pad_len
257 + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
259 return NT_STATUS_OK;
262 /*******************************************************************
263 Create and add the NTLMSSP sign/seal auth data.
264 ********************************************************************/
266 static NTSTATUS add_generic_auth_footer(struct gensec_security *gensec_security,
267 enum dcerpc_AuthLevel auth_level,
268 DATA_BLOB *rpc_out)
270 uint16_t data_and_pad_len = rpc_out->length
271 - DCERPC_RESPONSE_LENGTH
272 - DCERPC_AUTH_TRAILER_LENGTH;
273 DATA_BLOB auth_blob;
274 NTSTATUS status;
276 if (!gensec_security) {
277 return NT_STATUS_INVALID_PARAMETER;
280 switch (auth_level) {
281 case DCERPC_AUTH_LEVEL_PRIVACY:
282 /* Data portion is encrypted. */
283 status = gensec_seal_packet(gensec_security,
284 rpc_out->data,
285 rpc_out->data
286 + DCERPC_RESPONSE_LENGTH,
287 data_and_pad_len,
288 rpc_out->data,
289 rpc_out->length,
290 &auth_blob);
291 if (!NT_STATUS_IS_OK(status)) {
292 return status;
294 break;
296 case DCERPC_AUTH_LEVEL_INTEGRITY:
297 /* Data is signed. */
298 status = gensec_sign_packet(gensec_security,
299 rpc_out->data,
300 rpc_out->data
301 + DCERPC_RESPONSE_LENGTH,
302 data_and_pad_len,
303 rpc_out->data,
304 rpc_out->length,
305 &auth_blob);
306 if (!NT_STATUS_IS_OK(status)) {
307 return status;
309 break;
311 default:
312 /* Can't happen. */
313 smb_panic("bad auth level");
314 /* Notreached. */
315 return NT_STATUS_INVALID_PARAMETER;
318 /* Finally attach the blob. */
319 if (!data_blob_append(NULL, rpc_out,
320 auth_blob.data, auth_blob.length)) {
321 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
322 (unsigned int)auth_blob.length));
323 return NT_STATUS_NO_MEMORY;
325 data_blob_free(&auth_blob);
327 return NT_STATUS_OK;
330 /*******************************************************************
331 Check/unseal the NTLMSSP auth data. (Unseal in place).
332 ********************************************************************/
334 static NTSTATUS get_generic_auth_footer(struct gensec_security *gensec_security,
335 enum dcerpc_AuthLevel auth_level,
336 DATA_BLOB *data, DATA_BLOB *full_pkt,
337 DATA_BLOB *auth_token)
339 if (gensec_security == NULL) {
340 return NT_STATUS_INVALID_PARAMETER;
343 switch (auth_level) {
344 case DCERPC_AUTH_LEVEL_PRIVACY:
345 /* Data portion is encrypted. */
346 return gensec_unseal_packet(gensec_security,
347 data->data,
348 data->length,
349 full_pkt->data,
350 full_pkt->length,
351 auth_token);
353 case DCERPC_AUTH_LEVEL_INTEGRITY:
354 /* Data is signed. */
355 return gensec_check_packet(gensec_security,
356 data->data,
357 data->length,
358 full_pkt->data,
359 full_pkt->length,
360 auth_token);
362 default:
363 return NT_STATUS_INVALID_PARAMETER;
368 * @brief Append an auth footer according to what is the current mechanism
370 * @param auth The pipe_auth_data associated with the connection
371 * @param pad_len The padding used in the packet
372 * @param rpc_out Packet blob up to and including the auth header
374 * @return A NTSTATUS error code.
376 NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
377 size_t pad_len, DATA_BLOB *rpc_out)
379 struct gensec_security *gensec_security;
380 const char pad[DCERPC_AUTH_PAD_ALIGNMENT] = { 0, };
381 DATA_BLOB auth_info;
382 DATA_BLOB auth_blob;
383 NTSTATUS status;
385 if (auth->auth_type == DCERPC_AUTH_TYPE_NONE) {
386 return NT_STATUS_OK;
389 if (pad_len) {
390 SMB_ASSERT(pad_len <= ARRAY_SIZE(pad));
392 /* Copy the sign/seal padding data. */
393 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
394 return NT_STATUS_NO_MEMORY;
398 /* marshall the dcerpc_auth with an actually empty auth_blob.
399 * This is needed because the ntmlssp signature includes the
400 * auth header. We will append the actual blob later. */
401 auth_blob = data_blob_null;
402 status = dcerpc_push_dcerpc_auth(rpc_out->data,
403 auth->auth_type,
404 auth->auth_level,
405 pad_len,
406 auth->auth_context_id,
407 &auth_blob,
408 &auth_info);
409 if (!NT_STATUS_IS_OK(status)) {
410 return status;
413 /* append the header */
414 if (!data_blob_append(NULL, rpc_out,
415 auth_info.data, auth_info.length)) {
416 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
417 (unsigned int)auth_info.length));
418 return NT_STATUS_NO_MEMORY;
420 data_blob_free(&auth_info);
422 /* Generate any auth sign/seal and add the auth footer. */
423 switch (auth->auth_type) {
424 case DCERPC_AUTH_TYPE_NONE:
425 status = NT_STATUS_OK;
426 break;
427 default:
428 gensec_security = auth->auth_ctx;
429 status = add_generic_auth_footer(gensec_security,
430 auth->auth_level,
431 rpc_out);
432 break;
435 return status;
439 * @brief Check authentication for request/response packets
441 * @param auth The auth data for the connection
442 * @param pkt The actual ncacn_packet
443 * @param pkt_trailer [in][out] The stub_and_verifier part of the packet,
444 * the auth_trailer and padding will be removed.
445 * @param header_size The header size
446 * @param raw_pkt The whole raw packet data blob
448 * @return A NTSTATUS error code
450 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
451 struct ncacn_packet *pkt,
452 DATA_BLOB *pkt_trailer,
453 uint8_t header_size,
454 DATA_BLOB *raw_pkt)
456 struct gensec_security *gensec_security;
457 NTSTATUS status;
458 struct dcerpc_auth auth_info;
459 uint32_t auth_length;
460 DATA_BLOB full_pkt;
461 DATA_BLOB data;
464 * These check should be done in the caller.
466 SMB_ASSERT(raw_pkt->length == pkt->frag_length);
467 SMB_ASSERT(header_size <= pkt->frag_length);
468 SMB_ASSERT(pkt_trailer->length < pkt->frag_length);
469 SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length);
471 switch (auth->auth_level) {
472 case DCERPC_AUTH_LEVEL_PRIVACY:
473 DEBUG(10, ("Requested Privacy.\n"));
474 break;
476 case DCERPC_AUTH_LEVEL_INTEGRITY:
477 DEBUG(10, ("Requested Integrity.\n"));
478 break;
480 case DCERPC_AUTH_LEVEL_CONNECT:
481 if (pkt->auth_length != 0) {
482 break;
484 return NT_STATUS_OK;
486 case DCERPC_AUTH_LEVEL_NONE:
487 if (pkt->auth_length != 0) {
488 DEBUG(3, ("Got non-zero auth len on non "
489 "authenticated connection!\n"));
490 return NT_STATUS_INVALID_PARAMETER;
492 return NT_STATUS_OK;
494 default:
495 DEBUG(3, ("Unimplemented Auth Level %d",
496 auth->auth_level));
497 return NT_STATUS_INVALID_PARAMETER;
500 if (pkt->auth_length == 0) {
501 return NT_STATUS_INVALID_PARAMETER;
504 status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
505 &auth_info, &auth_length, false);
506 if (!NT_STATUS_IS_OK(status)) {
507 return status;
510 if (auth_info.auth_type != auth->auth_type) {
511 return NT_STATUS_INVALID_PARAMETER;
514 if (auth_info.auth_level != auth->auth_level) {
515 return NT_STATUS_INVALID_PARAMETER;
518 if (auth_info.auth_context_id != auth->auth_context_id) {
519 return NT_STATUS_INVALID_PARAMETER;
522 pkt_trailer->length -= auth_length;
523 data = data_blob_const(raw_pkt->data + header_size,
524 pkt_trailer->length);
525 full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length);
526 full_pkt.length -= auth_info.credentials.length;
528 switch (auth->auth_type) {
529 case DCERPC_AUTH_TYPE_NONE:
530 return NT_STATUS_OK;
532 default:
533 DEBUG(10, ("GENSEC auth\n"));
535 gensec_security = auth->auth_ctx;
536 status = get_generic_auth_footer(gensec_security,
537 auth->auth_level,
538 &data, &full_pkt,
539 &auth_info.credentials);
540 if (!NT_STATUS_IS_OK(status)) {
541 return status;
543 break;
546 /* TODO: remove later
547 * this is still needed because in the server code the
548 * pkt_trailer actually has a copy of the raw data, and they
549 * are still both used in later calls */
550 if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
551 if (pkt_trailer->length != data.length) {
552 return NT_STATUS_INVALID_PARAMETER;
554 memcpy(pkt_trailer->data, data.data, data.length);
557 pkt_trailer->length -= auth_info.auth_pad_length;
558 data_blob_free(&auth_info.credentials);
559 return NT_STATUS_OK;