s4:rpc_server: replace dce_conn->allow_request with auth->auth_finished
[Samba.git] / source4 / rpc_server / dcesrv_auth.c
blob98827ffd2141cb41e57cc902d7c0fae3fbbacf6c
1 /*
2 Unix SMB/CIFS implementation.
4 server side dcerpc authentication code
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Stefan (metze) Metzmacher 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "rpc_server/dcerpc_server.h"
25 #include "rpc_server/dcerpc_server_proto.h"
26 #include "rpc_server/common/proto.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "auth/credentials/credentials.h"
30 #include "auth/gensec/gensec.h"
31 #include "auth/auth.h"
32 #include "param/param.h"
33 #include "librpc/rpc/rpc_common.h"
35 static bool dcesrv_auth_prepare_gensec(struct dcesrv_call_state *call)
37 struct cli_credentials *server_credentials = NULL;
38 struct dcesrv_connection *dce_conn = call->conn;
39 struct dcesrv_auth *auth = call->auth_state;
40 bool want_header_signing = false;
41 NTSTATUS status;
43 if (auth->auth_started) {
44 return false;
47 auth->auth_started = true;
49 if (auth->auth_invalid) {
50 return false;
53 if (auth->auth_finished) {
54 return false;
57 if (auth->gensec_security != NULL) {
58 return false;
61 switch (call->in_auth_info.auth_level) {
62 case DCERPC_AUTH_LEVEL_CONNECT:
63 case DCERPC_AUTH_LEVEL_CALL:
64 case DCERPC_AUTH_LEVEL_PACKET:
65 case DCERPC_AUTH_LEVEL_INTEGRITY:
66 case DCERPC_AUTH_LEVEL_PRIVACY:
68 * We evaluate auth_type only if auth_level was valid
70 break;
71 default:
73 * Setting DCERPC_AUTH_LEVEL_NONE,
74 * gives the caller the reject_reason
75 * as auth_context_id.
77 * Note: DCERPC_AUTH_LEVEL_NONE == 1
79 auth->auth_type = DCERPC_AUTH_TYPE_NONE;
80 auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
81 auth->auth_context_id = DCERPC_BIND_NAK_REASON_NOT_SPECIFIED;
82 return false;
85 auth->auth_type = call->in_auth_info.auth_type;
86 auth->auth_level = call->in_auth_info.auth_level;
87 auth->auth_context_id = call->in_auth_info.auth_context_id;
89 server_credentials
90 = cli_credentials_init(auth);
91 if (!server_credentials) {
92 DEBUG(1, ("Failed to init server credentials\n"));
93 return false;
96 cli_credentials_set_conf(server_credentials, call->conn->dce_ctx->lp_ctx);
97 status = cli_credentials_set_machine_account(server_credentials, call->conn->dce_ctx->lp_ctx);
98 if (!NT_STATUS_IS_OK(status)) {
99 DEBUG(1, ("Failed to obtain server credentials: %s\n",
100 nt_errstr(status)));
101 return false;
104 status = samba_server_gensec_start(auth,
105 call->event_ctx,
106 call->msg_ctx,
107 call->conn->dce_ctx->lp_ctx,
108 server_credentials,
109 NULL,
110 &auth->gensec_security);
111 if (!NT_STATUS_IS_OK(status)) {
112 DEBUG(1, ("Failed to call samba_server_gensec_start %s\n",
113 nt_errstr(status)));
114 return false;
118 * We have to call this because we set the target_service for
119 * Kerberos to NULL above, and in any case we wish to log a
120 * more specific service target.
123 status = gensec_set_target_service_description(auth->gensec_security,
124 "DCE/RPC");
125 if (!NT_STATUS_IS_OK(status)) {
126 DEBUG(1, ("Failed to call gensec_set_target_service_description %s\n",
127 nt_errstr(status)));
128 return false;
131 if (call->conn->remote_address != NULL) {
132 status = gensec_set_remote_address(auth->gensec_security,
133 call->conn->remote_address);
134 if (!NT_STATUS_IS_OK(status)) {
135 DEBUG(1, ("Failed to call gensec_set_remote_address() %s\n",
136 nt_errstr(status)));
137 return false;
141 if (call->conn->local_address != NULL) {
142 status = gensec_set_local_address(auth->gensec_security,
143 call->conn->local_address);
144 if (!NT_STATUS_IS_OK(status)) {
145 DEBUG(1, ("Failed to call gensec_set_local_address() %s\n",
146 nt_errstr(status)));
147 return false;
151 status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_type,
152 auth->auth_level);
153 if (!NT_STATUS_IS_OK(status)) {
154 const char *backend_name =
155 gensec_get_name_by_authtype(auth->gensec_security,
156 auth->auth_type);
158 DEBUG(3, ("Failed to start GENSEC mechanism for DCERPC server: "
159 "auth_type=%d (%s), auth_level=%d: %s\n",
160 (int)auth->auth_type, backend_name,
161 (int)auth->auth_level,
162 nt_errstr(status)));
165 * Setting DCERPC_AUTH_LEVEL_NONE,
166 * gives the caller the reject_reason
167 * as auth_context_id.
169 * Note: DCERPC_AUTH_LEVEL_NONE == 1
171 auth->auth_type = DCERPC_AUTH_TYPE_NONE;
172 auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
173 if (backend_name != NULL) {
174 auth->auth_context_id =
175 DCERPC_BIND_NAK_REASON_INVALID_CHECKSUM;
176 } else {
177 auth->auth_context_id =
178 DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE;
180 return false;
183 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
184 auth->client_hdr_signing = true;
185 want_header_signing = true;
188 if (want_header_signing) {
189 want_header_signing = gensec_have_feature(auth->gensec_security,
190 GENSEC_FEATURE_SIGN_PKT_HEADER);
193 if (want_header_signing) {
194 want_header_signing = lpcfg_parm_bool(dce_conn->dce_ctx->lp_ctx,
195 NULL,
196 "dcesrv",
197 "header signing",
198 true);
201 if (want_header_signing) {
202 gensec_want_feature(auth->gensec_security,
203 GENSEC_FEATURE_SIGN_PKT_HEADER);
204 auth->hdr_signing = true;
207 return true;
210 static void log_successful_dcesrv_authz_event(struct dcesrv_call_state *call)
212 struct dcesrv_auth *auth = call->auth_state;
213 enum dcerpc_transport_t transport =
214 dcerpc_binding_get_transport(call->conn->endpoint->ep_description);
215 const char *auth_type = derpc_transport_string_by_transport(transport);
216 const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
218 if (transport == NCACN_NP) {
219 transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
223 * Log the authorization to this RPC interface. This
224 * covered ncacn_np pass-through auth, and anonymous
225 * DCE/RPC (eg epmapper, netlogon etc)
227 log_successful_authz_event(call->conn->msg_ctx,
228 call->conn->dce_ctx->lp_ctx,
229 call->conn->remote_address,
230 call->conn->local_address,
231 "DCE/RPC",
232 auth_type,
233 transport_protection,
234 auth->session_info);
238 parse any auth information from a dcerpc bind request
239 return false if we can't handle the auth request for some
240 reason (in which case we send a bind_nak)
242 bool dcesrv_auth_bind(struct dcesrv_call_state *call)
244 struct ncacn_packet *pkt = &call->pkt;
245 struct dcesrv_auth *auth = call->auth_state;
246 NTSTATUS status;
248 if (pkt->auth_length == 0) {
249 auth->auth_type = DCERPC_AUTH_TYPE_NONE;
250 auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
251 auth->auth_context_id = 0;
252 auth->auth_started = true;
254 log_successful_dcesrv_authz_event(call);
256 return true;
259 status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info,
260 &call->in_auth_info,
261 NULL, true);
262 if (!NT_STATUS_IS_OK(status)) {
264 * Setting DCERPC_AUTH_LEVEL_NONE,
265 * gives the caller the reject_reason
266 * as auth_context_id.
268 * Note: DCERPC_AUTH_LEVEL_NONE == 1
270 auth->auth_type = DCERPC_AUTH_TYPE_NONE;
271 auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
272 auth->auth_context_id =
273 DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED;
274 return false;
277 return dcesrv_auth_prepare_gensec(call);
280 NTSTATUS dcesrv_auth_complete(struct dcesrv_call_state *call, NTSTATUS status)
282 struct dcesrv_auth *auth = call->auth_state;
283 const char *pdu = "<unknown>";
285 switch (call->pkt.ptype) {
286 case DCERPC_PKT_BIND:
287 pdu = "BIND";
288 break;
289 case DCERPC_PKT_ALTER:
290 pdu = "ALTER";
291 break;
292 case DCERPC_PKT_AUTH3:
293 pdu = "AUTH3";
294 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
295 DEBUG(4, ("GENSEC not finished at at %s\n", pdu));
296 return NT_STATUS_RPC_SEC_PKG_ERROR;
298 break;
299 default:
300 return NT_STATUS_INTERNAL_ERROR;
303 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
304 return NT_STATUS_OK;
307 if (!NT_STATUS_IS_OK(status)) {
308 DEBUG(4, ("GENSEC mech rejected the incoming authentication "
309 "at %s: %s\n", pdu, nt_errstr(status)));
310 return status;
313 status = gensec_session_info(auth->gensec_security,
314 auth,
315 &auth->session_info);
316 if (!NT_STATUS_IS_OK(status)) {
317 DEBUG(1, ("Failed to establish session_info: %s\n",
318 nt_errstr(status)));
319 return status;
321 auth->auth_finished = true;
323 if (call->pkt.ptype != DCERPC_PKT_AUTH3) {
324 return NT_STATUS_OK;
327 if (call->out_auth_info->credentials.length != 0) {
328 DEBUG(4, ("GENSEC produced output token (len=%zu) at %s\n",
329 call->out_auth_info->credentials.length, pdu));
330 return NT_STATUS_RPC_SEC_PKG_ERROR;
333 return NT_STATUS_OK;
337 add any auth information needed in a bind ack, and process the authentication
338 information found in the bind.
340 NTSTATUS dcesrv_auth_prepare_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
342 struct dcesrv_connection *dce_conn = call->conn;
343 struct dcesrv_auth *auth = call->auth_state;
345 dce_conn->allow_alter = true;
347 if (call->pkt.auth_length == 0) {
348 auth->auth_finished = true;
349 return NT_STATUS_OK;
352 /* We can't work without an existing gensec state */
353 if (auth->gensec_security == NULL) {
354 return NT_STATUS_INTERNAL_ERROR;
357 if (auth->hdr_signing) {
358 pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
361 call->_out_auth_info = (struct dcerpc_auth) {
362 .auth_type = auth->auth_type,
363 .auth_level = auth->auth_level,
364 .auth_context_id = auth->auth_context_id,
366 call->out_auth_info = &call->_out_auth_info;
368 return NT_STATUS_OK;
372 process the final stage of a auth request
374 bool dcesrv_auth_prepare_auth3(struct dcesrv_call_state *call)
376 struct ncacn_packet *pkt = &call->pkt;
377 struct dcesrv_auth *auth = call->auth_state;
378 NTSTATUS status;
380 if (pkt->auth_length == 0) {
381 return false;
384 if (auth->auth_finished) {
385 return false;
388 /* We can't work without an existing gensec state */
389 if (auth->gensec_security == NULL) {
390 return false;
393 status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info,
394 &call->in_auth_info, NULL, true);
395 if (!NT_STATUS_IS_OK(status)) {
397 * Windows returns DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY
398 * instead of DCERPC_NCA_S_PROTO_ERROR.
400 call->fault_code = DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY;
401 return false;
404 if (call->in_auth_info.auth_type != auth->auth_type) {
405 return false;
408 if (call->in_auth_info.auth_level != auth->auth_level) {
409 return false;
412 if (call->in_auth_info.auth_context_id != auth->auth_context_id) {
413 return false;
416 call->_out_auth_info = (struct dcerpc_auth) {
417 .auth_type = auth->auth_type,
418 .auth_level = auth->auth_level,
419 .auth_context_id = auth->auth_context_id,
421 call->out_auth_info = &call->_out_auth_info;
423 return true;
427 parse any auth information from a dcerpc alter request
428 return false if we can't handle the auth request for some
429 reason (in which case we send a bind_nak (is this true for here?))
431 bool dcesrv_auth_alter(struct dcesrv_call_state *call)
433 struct ncacn_packet *pkt = &call->pkt;
434 struct dcesrv_auth *auth = call->auth_state;
435 NTSTATUS status;
437 /* on a pure interface change there is no auth blob */
438 if (pkt->auth_length == 0) {
439 if (!auth->auth_finished) {
440 return false;
442 return true;
445 if (auth->auth_finished) {
446 call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
447 return false;
450 /* We can't work without an existing gensec state */
451 if (auth->gensec_security == NULL) {
452 return false;
455 status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.alter.auth_info,
456 &call->in_auth_info, NULL, true);
457 if (!NT_STATUS_IS_OK(status)) {
458 call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
459 return false;
462 if (call->in_auth_info.auth_type == DCERPC_AUTH_TYPE_NONE) {
463 call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
464 return false;
467 if (call->in_auth_info.auth_type != auth->auth_type) {
468 return false;
471 if (call->in_auth_info.auth_level != auth->auth_level) {
472 return false;
475 if (call->in_auth_info.auth_context_id != auth->auth_context_id) {
476 return false;
479 return true;
483 add any auth information needed in a alter ack, and process the authentication
484 information found in the alter.
486 NTSTATUS dcesrv_auth_prepare_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
488 struct dcesrv_auth *auth = call->auth_state;
490 /* on a pure interface change there is no auth_info structure
491 setup */
492 if (call->pkt.auth_length == 0) {
493 return NT_STATUS_OK;
496 if (auth->gensec_security == NULL) {
497 return NT_STATUS_INTERNAL_ERROR;
500 call->_out_auth_info = (struct dcerpc_auth) {
501 .auth_type = auth->auth_type,
502 .auth_level = auth->auth_level,
503 .auth_context_id = auth->auth_context_id,
505 call->out_auth_info = &call->_out_auth_info;
507 return NT_STATUS_OK;
511 check credentials on a packet
513 bool dcesrv_auth_pkt_pull(struct dcesrv_call_state *call,
514 DATA_BLOB *full_packet,
515 uint8_t required_flags,
516 uint8_t optional_flags,
517 uint8_t payload_offset,
518 DATA_BLOB *payload_and_verifier)
520 struct ncacn_packet *pkt = &call->pkt;
521 struct dcesrv_auth *auth = call->auth_state;
522 const struct dcerpc_auth tmp_auth = {
523 .auth_type = auth->auth_type,
524 .auth_level = auth->auth_level,
525 .auth_context_id = auth->auth_context_id,
527 NTSTATUS status;
529 if (!auth->auth_finished) {
530 call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
531 return false;
534 if (auth->auth_invalid) {
535 return false;
538 status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
539 auth->gensec_security,
540 call,
541 pkt->ptype,
542 required_flags,
543 optional_flags,
544 payload_offset,
545 payload_and_verifier,
546 full_packet,
547 pkt);
548 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
549 call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
550 return false;
552 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL)) {
553 call->fault_code = DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL;
554 return false;
556 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
557 call->fault_code = DCERPC_FAULT_SEC_PKG_ERROR;
558 return false;
560 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
561 call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
562 return false;
564 if (!NT_STATUS_IS_OK(status)) {
565 return false;
568 return true;
572 push a signed or sealed dcerpc request packet into a blob
574 bool dcesrv_auth_pkt_push(struct dcesrv_call_state *call,
575 DATA_BLOB *blob, size_t sig_size,
576 uint8_t payload_offset,
577 const DATA_BLOB *payload,
578 const struct ncacn_packet *pkt)
580 struct dcesrv_auth *auth = call->auth_state;
581 const struct dcerpc_auth tmp_auth = {
582 .auth_type = auth->auth_type,
583 .auth_level = auth->auth_level,
584 .auth_context_id = auth->auth_context_id,
586 NTSTATUS status;
588 status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
589 auth->gensec_security,
590 call, blob, sig_size,
591 payload_offset,
592 payload,
593 pkt);
594 return NT_STATUS_IS_OK(status);