ctdb-tests: Update statd-callout tests to handle both modes
[samba4-gss.git] / source3 / librpc / rpc / dcerpc_helpers.c
blob5310e4a6612995cb2c85da92288759cbf095d601
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/rpc/dcerpc_internal.h"
24 #include "librpc/rpc/dcerpc_util.h"
25 #include "librpc/gen_ndr/ndr_dcerpc.h"
26 #include "librpc/crypto/gse.h"
27 #include "auth/gensec/gensec.h"
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_RPC_PARSE
32 /**
33 * @brief NDR Encodes a ncacn_packet
35 * @param mem_ctx The memory context the blob will be allocated on
36 * @param ptype The DCERPC packet type
37 * @param pfc_flags The DCERPC PFC Flags
38 * @param auth_length The length of the trailing auth blob
39 * @param call_id The call ID
40 * @param u The payload of the packet
41 * @param blob [out] The encoded blob if successful
43 * @return an NTSTATUS error code
45 NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx,
46 enum dcerpc_pkt_type ptype,
47 uint8_t pfc_flags,
48 uint16_t auth_length,
49 uint32_t call_id,
50 union dcerpc_payload *u,
51 DATA_BLOB *blob)
53 struct ncacn_packet r;
54 enum ndr_err_code ndr_err;
56 r.rpc_vers = 5;
57 r.rpc_vers_minor = 0;
58 r.ptype = ptype;
59 r.pfc_flags = pfc_flags;
60 r.drep[0] = DCERPC_DREP_LE;
61 r.drep[1] = 0;
62 r.drep[2] = 0;
63 r.drep[3] = 0;
64 r.auth_length = auth_length;
65 r.call_id = call_id;
66 r.u = *u;
68 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
69 (ndr_push_flags_fn_t)ndr_push_ncacn_packet);
70 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
71 return ndr_map_error2ntstatus(ndr_err);
74 dcerpc_set_frag_length(blob, blob->length);
77 if (DEBUGLEVEL >= 10) {
78 /* set frag len for print function */
79 r.frag_length = blob->length;
80 NDR_PRINT_DEBUG(ncacn_packet, &r);
83 return NT_STATUS_OK;
86 /**
87 * @brief NDR Encodes a dcerpc_auth structure
89 * @param mem_ctx The memory context the blob will be allocated on
90 * @param auth_type The DCERPC Authentication Type
91 * @param auth_level The DCERPC Authentication Level
92 * @param auth_pad_length The padding added to the packet this blob will be
93 * appended to.
94 * @param auth_context_id The context id
95 * @param credentials The authentication credentials blob (signature)
96 * @param blob [out] The encoded blob if successful
98 * @return a NTSTATUS error code
100 NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx,
101 enum dcerpc_AuthType auth_type,
102 enum dcerpc_AuthLevel auth_level,
103 uint8_t auth_pad_length,
104 uint32_t auth_context_id,
105 const DATA_BLOB *credentials,
106 DATA_BLOB *blob)
108 struct dcerpc_auth r;
109 enum ndr_err_code ndr_err;
111 r.auth_type = auth_type;
112 r.auth_level = auth_level;
113 r.auth_pad_length = auth_pad_length;
114 r.auth_reserved = 0;
115 r.auth_context_id = auth_context_id;
116 r.credentials = *credentials;
118 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
119 (ndr_push_flags_fn_t)ndr_push_dcerpc_auth);
120 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
121 return ndr_map_error2ntstatus(ndr_err);
124 if (DEBUGLEVEL >= 10) {
125 NDR_PRINT_DEBUG(dcerpc_auth, &r);
128 return NT_STATUS_OK;
132 * @brief Calculate how much data we can in a packet, including calculating
133 * auth token and pad lengths.
135 * @param auth The pipe_auth_data structure for this pipe.
136 * @param header_len The length of the packet header
137 * @param data_left The data left in the send buffer
138 * @param max_xmit_frag The max fragment size.
139 * @param data_to_send [out] The max data we will send in the pdu
140 * @param frag_len [out] The total length of the fragment
141 * @param auth_len [out] The length of the auth trailer
142 * @param pad_len [out] The padding to be applied
144 * @return A NT Error status code.
146 NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
147 size_t header_len, size_t data_left,
148 size_t max_xmit_frag,
149 size_t *data_to_send, size_t *frag_len,
150 size_t *auth_len, size_t *pad_len)
152 size_t max_len;
153 size_t mod_len;
154 struct gensec_security *gensec_security;
156 /* no auth token cases first */
157 switch (auth->auth_level) {
158 case DCERPC_AUTH_LEVEL_NONE:
159 case DCERPC_AUTH_LEVEL_CONNECT:
160 max_len = max_xmit_frag - header_len;
161 *data_to_send = MIN(max_len, data_left);
162 *pad_len = 0;
163 *auth_len = 0;
164 *frag_len = header_len + *data_to_send;
165 return NT_STATUS_OK;
167 case DCERPC_AUTH_LEVEL_PRIVACY:
168 break;
170 case DCERPC_AUTH_LEVEL_INTEGRITY:
171 break;
173 case DCERPC_AUTH_LEVEL_PACKET:
174 break;
176 default:
177 return NT_STATUS_INVALID_PARAMETER;
181 /* Sign/seal case, calculate auth and pad lengths */
183 max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH;
185 /* Treat the same for all authenticated rpc requests. */
186 switch (auth->auth_type) {
187 case DCERPC_AUTH_TYPE_SPNEGO:
188 case DCERPC_AUTH_TYPE_NTLMSSP:
189 case DCERPC_AUTH_TYPE_KRB5:
190 case DCERPC_AUTH_TYPE_SCHANNEL:
191 gensec_security = auth->auth_ctx;
192 mod_len = (max_len % DCERPC_AUTH_PAD_ALIGNMENT);
193 *auth_len = gensec_sig_size(gensec_security, max_len - mod_len);
194 if (*auth_len == 0) {
195 return NT_STATUS_INTERNAL_ERROR;
197 break;
198 default:
199 return NT_STATUS_INVALID_PARAMETER;
202 max_len -= *auth_len;
203 mod_len = (max_len % DCERPC_AUTH_PAD_ALIGNMENT);
204 max_len -= mod_len;
206 *data_to_send = MIN(max_len, data_left);
208 *pad_len = DCERPC_AUTH_PAD_LENGTH(*data_to_send);
210 *frag_len = header_len + *data_to_send + *pad_len
211 + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
213 return NT_STATUS_OK;
216 /*******************************************************************
217 Create and add the NTLMSSP sign/seal auth data.
218 ********************************************************************/
220 static NTSTATUS add_generic_auth_footer(struct gensec_security *gensec_security,
221 enum dcerpc_AuthLevel auth_level,
222 DATA_BLOB *rpc_out)
224 uint16_t data_and_pad_len = rpc_out->length
225 - DCERPC_RESPONSE_LENGTH
226 - DCERPC_AUTH_TRAILER_LENGTH;
227 DATA_BLOB auth_blob;
228 NTSTATUS status;
230 if (!gensec_security) {
231 return NT_STATUS_INVALID_PARAMETER;
234 switch (auth_level) {
235 case DCERPC_AUTH_LEVEL_PRIVACY:
236 /* Data portion is encrypted. */
237 status = gensec_seal_packet(gensec_security,
238 rpc_out->data,
239 rpc_out->data
240 + DCERPC_RESPONSE_LENGTH,
241 data_and_pad_len,
242 rpc_out->data,
243 rpc_out->length,
244 &auth_blob);
245 if (!NT_STATUS_IS_OK(status)) {
246 return status;
248 break;
250 case DCERPC_AUTH_LEVEL_INTEGRITY:
251 case DCERPC_AUTH_LEVEL_PACKET:
252 /* Data is signed. */
253 status = gensec_sign_packet(gensec_security,
254 rpc_out->data,
255 rpc_out->data
256 + DCERPC_RESPONSE_LENGTH,
257 data_and_pad_len,
258 rpc_out->data,
259 rpc_out->length,
260 &auth_blob);
261 if (!NT_STATUS_IS_OK(status)) {
262 return status;
264 break;
266 default:
267 /* Can't happen. */
268 smb_panic("bad auth level");
269 /* Notreached. */
270 return NT_STATUS_INVALID_PARAMETER;
273 /* Finally attach the blob. */
274 if (!data_blob_append(NULL, rpc_out,
275 auth_blob.data, auth_blob.length)) {
276 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
277 (unsigned int)auth_blob.length));
278 return NT_STATUS_NO_MEMORY;
280 data_blob_free(&auth_blob);
282 return NT_STATUS_OK;
285 /*******************************************************************
286 Check/unseal the NTLMSSP auth data. (Unseal in place).
287 ********************************************************************/
289 static NTSTATUS get_generic_auth_footer(struct gensec_security *gensec_security,
290 enum dcerpc_AuthLevel auth_level,
291 DATA_BLOB *data, DATA_BLOB *full_pkt,
292 DATA_BLOB *auth_token)
294 if (gensec_security == NULL) {
295 return NT_STATUS_INVALID_PARAMETER;
298 switch (auth_level) {
299 case DCERPC_AUTH_LEVEL_PRIVACY:
300 /* Data portion is encrypted. */
301 return gensec_unseal_packet(gensec_security,
302 data->data,
303 data->length,
304 full_pkt->data,
305 full_pkt->length,
306 auth_token);
308 case DCERPC_AUTH_LEVEL_INTEGRITY:
309 case DCERPC_AUTH_LEVEL_PACKET:
310 /* Data is signed. */
311 return gensec_check_packet(gensec_security,
312 data->data,
313 data->length,
314 full_pkt->data,
315 full_pkt->length,
316 auth_token);
318 default:
319 return NT_STATUS_INVALID_PARAMETER;
324 * @brief Append an auth footer according to what is the current mechanism
326 * @param auth The pipe_auth_data associated with the connection
327 * @param pad_len The padding used in the packet
328 * @param rpc_out Packet blob up to and including the auth header
330 * @return A NTSTATUS error code.
332 NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
333 size_t pad_len, DATA_BLOB *rpc_out)
335 struct gensec_security *gensec_security;
336 const char pad[DCERPC_AUTH_PAD_ALIGNMENT] = { 0, };
337 DATA_BLOB auth_info;
338 DATA_BLOB auth_blob;
339 NTSTATUS status;
341 if (auth->auth_type == DCERPC_AUTH_TYPE_NONE) {
342 return NT_STATUS_OK;
345 if (pad_len) {
346 SMB_ASSERT(pad_len <= ARRAY_SIZE(pad));
348 /* Copy the sign/seal padding data. */
349 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
350 return NT_STATUS_NO_MEMORY;
354 /* marshall the dcerpc_auth with an actually empty auth_blob.
355 * This is needed because the ntmlssp signature includes the
356 * auth header. We will append the actual blob later. */
357 auth_blob = data_blob_null;
358 status = dcerpc_push_dcerpc_auth(rpc_out->data,
359 auth->auth_type,
360 auth->auth_level,
361 pad_len,
362 auth->auth_context_id,
363 &auth_blob,
364 &auth_info);
365 if (!NT_STATUS_IS_OK(status)) {
366 return status;
369 /* append the header */
370 if (!data_blob_append(NULL, rpc_out,
371 auth_info.data, auth_info.length)) {
372 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
373 (unsigned int)auth_info.length));
374 return NT_STATUS_NO_MEMORY;
376 data_blob_free(&auth_info);
378 /* Generate any auth sign/seal and add the auth footer. */
379 switch (auth->auth_type) {
380 case DCERPC_AUTH_TYPE_NONE:
381 status = NT_STATUS_OK;
382 break;
383 default:
384 gensec_security = auth->auth_ctx;
385 status = add_generic_auth_footer(gensec_security,
386 auth->auth_level,
387 rpc_out);
388 break;
391 return status;
395 * @brief Check authentication for request/response packets
397 * @param auth The auth data for the connection
398 * @param pkt The actual ncacn_packet
399 * @param pkt_trailer [in][out] The stub_and_verifier part of the packet,
400 * the auth_trailer and padding will be removed.
401 * @param header_size The header size
402 * @param raw_pkt The whole raw packet data blob
404 * @return A NTSTATUS error code
406 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
407 struct ncacn_packet *pkt,
408 DATA_BLOB *pkt_trailer,
409 uint8_t header_size,
410 DATA_BLOB *raw_pkt)
412 struct gensec_security *gensec_security;
413 NTSTATUS status;
414 struct dcerpc_auth auth_info;
415 uint32_t auth_length;
416 DATA_BLOB full_pkt;
417 DATA_BLOB data;
420 * These check should be done in the caller.
422 SMB_ASSERT(raw_pkt->length == pkt->frag_length);
423 SMB_ASSERT(header_size <= pkt->frag_length);
424 SMB_ASSERT(pkt_trailer->length < pkt->frag_length);
425 SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length);
427 switch (auth->auth_level) {
428 case DCERPC_AUTH_LEVEL_PRIVACY:
429 DEBUG(10, ("Requested Privacy.\n"));
430 break;
432 case DCERPC_AUTH_LEVEL_INTEGRITY:
433 DEBUG(10, ("Requested Integrity.\n"));
434 break;
436 case DCERPC_AUTH_LEVEL_PACKET:
437 DEBUG(10, ("Requested packet.\n"));
438 break;
440 case DCERPC_AUTH_LEVEL_CONNECT:
441 if (pkt->auth_length != 0) {
442 break;
444 return NT_STATUS_OK;
446 case DCERPC_AUTH_LEVEL_NONE:
447 if (pkt->auth_length != 0) {
448 DEBUG(3, ("Got non-zero auth len on non "
449 "authenticated connection!\n"));
450 return NT_STATUS_INVALID_PARAMETER;
452 return NT_STATUS_OK;
454 default:
455 DEBUG(3, ("Unimplemented Auth Level %d\n",
456 auth->auth_level));
457 return NT_STATUS_INVALID_PARAMETER;
460 if (pkt->auth_length == 0) {
461 return NT_STATUS_INVALID_PARAMETER;
464 status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
465 &auth_info, &auth_length, false);
466 if (!NT_STATUS_IS_OK(status)) {
467 return status;
470 if (auth_info.auth_type != auth->auth_type) {
471 return NT_STATUS_INVALID_PARAMETER;
474 if (auth_info.auth_level != auth->auth_level) {
475 return NT_STATUS_INVALID_PARAMETER;
478 if (auth_info.auth_context_id != auth->auth_context_id) {
479 return NT_STATUS_INVALID_PARAMETER;
482 pkt_trailer->length -= auth_length;
483 data = data_blob_const(raw_pkt->data + header_size,
484 pkt_trailer->length);
485 full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length);
486 full_pkt.length -= auth_info.credentials.length;
488 switch (auth->auth_type) {
489 case DCERPC_AUTH_TYPE_NONE:
490 return NT_STATUS_OK;
492 default:
493 DEBUG(10, ("GENSEC auth\n"));
495 gensec_security = auth->auth_ctx;
496 status = get_generic_auth_footer(gensec_security,
497 auth->auth_level,
498 &data, &full_pkt,
499 &auth_info.credentials);
500 if (!NT_STATUS_IS_OK(status)) {
501 return status;
503 break;
506 /* TODO: remove later
507 * this is still needed because in the server code the
508 * pkt_trailer actually has a copy of the raw data, and they
509 * are still both used in later calls */
510 if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
511 if (pkt_trailer->length != data.length) {
512 return NT_STATUS_INVALID_PARAMETER;
514 memcpy(pkt_trailer->data, data.data, data.length);
517 pkt_trailer->length -= auth_info.auth_pad_length;
518 data_blob_free(&auth_info.credentials);
519 return NT_STATUS_OK;