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/>.
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"
36 parse any auth information from a dcerpc bind request
37 return false if we can't handle the auth request for some
38 reason (in which case we send a bind_nak)
40 bool dcesrv_auth_bind(struct dcesrv_call_state
*call
)
42 struct cli_credentials
*server_credentials
= NULL
;
43 struct ncacn_packet
*pkt
= &call
->pkt
;
44 struct dcesrv_connection
*dce_conn
= call
->conn
;
45 struct dcesrv_auth
*auth
= &dce_conn
->auth_state
;
48 if (pkt
->auth_length
== 0) {
49 enum dcerpc_transport_t transport
=
50 dcerpc_binding_get_transport(call
->conn
->endpoint
->ep_description
);
51 const char *auth_type
= derpc_transport_string_by_transport(transport
);
52 auth
->auth_type
= DCERPC_AUTH_TYPE_NONE
;
53 auth
->auth_level
= DCERPC_AUTH_LEVEL_NONE
;
54 auth
->auth_context_id
= 0;
57 * Log the authorization to this RPC interface. This
58 * covered ncacn_np pass-through auth, and anonymous
59 * DCE/RPC (eg epmapper, netlogon etc)
61 log_successful_authz_event(call
->conn
->remote_address
,
62 call
->conn
->local_address
,
65 call
->conn
->auth_state
.session_info
);
70 status
= dcerpc_pull_auth_trailer(pkt
, call
, &pkt
->u
.bind
.auth_info
,
73 if (!NT_STATUS_IS_OK(status
)) {
75 * Setting DCERPC_AUTH_LEVEL_NONE,
76 * gives the caller the reject_reason
79 * Note: DCERPC_AUTH_LEVEL_NONE == 1
81 auth
->auth_type
= DCERPC_AUTH_TYPE_NONE
;
82 auth
->auth_level
= DCERPC_AUTH_LEVEL_NONE
;
83 auth
->auth_context_id
=
84 DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED
;
88 switch (call
->in_auth_info
.auth_level
) {
89 case DCERPC_AUTH_LEVEL_CONNECT
:
90 case DCERPC_AUTH_LEVEL_CALL
:
91 case DCERPC_AUTH_LEVEL_PACKET
:
92 case DCERPC_AUTH_LEVEL_INTEGRITY
:
93 case DCERPC_AUTH_LEVEL_PRIVACY
:
95 * We evaluate auth_type only if auth_level was valid
100 * Setting DCERPC_AUTH_LEVEL_NONE,
101 * gives the caller the reject_reason
102 * as auth_context_id.
104 * Note: DCERPC_AUTH_LEVEL_NONE == 1
106 auth
->auth_type
= DCERPC_AUTH_TYPE_NONE
;
107 auth
->auth_level
= DCERPC_AUTH_LEVEL_NONE
;
108 auth
->auth_context_id
= DCERPC_BIND_NAK_REASON_NOT_SPECIFIED
;
112 auth
->auth_type
= call
->in_auth_info
.auth_type
;
113 auth
->auth_level
= call
->in_auth_info
.auth_level
;
114 auth
->auth_context_id
= call
->in_auth_info
.auth_context_id
;
117 = cli_credentials_init(call
);
118 if (!server_credentials
) {
119 DEBUG(1, ("Failed to init server credentials\n"));
123 cli_credentials_set_conf(server_credentials
, call
->conn
->dce_ctx
->lp_ctx
);
124 status
= cli_credentials_set_machine_account(server_credentials
, call
->conn
->dce_ctx
->lp_ctx
);
125 if (!NT_STATUS_IS_OK(status
)) {
126 DEBUG(1, ("Failed to obtain server credentials: %s\n",
131 status
= samba_server_gensec_start(dce_conn
, call
->event_ctx
,
133 call
->conn
->dce_ctx
->lp_ctx
,
136 &auth
->gensec_security
);
137 if (!NT_STATUS_IS_OK(status
)) {
138 DEBUG(1, ("Failed to call samba_server_gensec_start %s\n",
144 * We have to call this because we set the target_service for
145 * Kerberos to NULL above, and in any case we wish to log a
146 * more specific service target.
149 status
= gensec_set_target_service_description(auth
->gensec_security
,
151 if (!NT_STATUS_IS_OK(status
)) {
152 DEBUG(1, ("Failed to call gensec_set_target_service_description %s\n",
157 if (call
->conn
->remote_address
!= NULL
) {
158 status
= gensec_set_remote_address(auth
->gensec_security
,
159 call
->conn
->remote_address
);
160 if (!NT_STATUS_IS_OK(status
)) {
161 DEBUG(1, ("Failed to call gensec_set_remote_address() %s\n",
167 if (call
->conn
->local_address
!= NULL
) {
168 status
= gensec_set_local_address(auth
->gensec_security
,
169 call
->conn
->local_address
);
170 if (!NT_STATUS_IS_OK(status
)) {
171 DEBUG(1, ("Failed to call gensec_set_local_address() %s\n",
177 status
= gensec_start_mech_by_authtype(auth
->gensec_security
, auth
->auth_type
,
179 if (!NT_STATUS_IS_OK(status
)) {
180 const char *backend_name
=
181 gensec_get_name_by_authtype(auth
->gensec_security
,
184 DEBUG(3, ("Failed to start GENSEC mechanism for DCERPC server: "
185 "auth_type=%d (%s), auth_level=%d: %s\n",
186 (int)auth
->auth_type
, backend_name
,
187 (int)auth
->auth_level
,
191 * Setting DCERPC_AUTH_LEVEL_NONE,
192 * gives the caller the reject_reason
193 * as auth_context_id.
195 * Note: DCERPC_AUTH_LEVEL_NONE == 1
197 auth
->auth_type
= DCERPC_AUTH_TYPE_NONE
;
198 auth
->auth_level
= DCERPC_AUTH_LEVEL_NONE
;
199 if (backend_name
!= NULL
) {
200 auth
->auth_context_id
=
201 DCERPC_BIND_NAK_REASON_INVALID_CHECKSUM
;
203 auth
->auth_context_id
=
204 DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE
;
213 add any auth information needed in a bind ack, and process the authentication
214 information found in the bind.
216 NTSTATUS
dcesrv_auth_bind_ack(struct dcesrv_call_state
*call
, struct ncacn_packet
*pkt
)
218 struct dcesrv_connection
*dce_conn
= call
->conn
;
220 bool want_header_signing
= false;
222 dce_conn
->allow_alter
= true;
223 dce_conn
->allow_auth3
= true;
225 if (call
->pkt
.auth_length
== 0) {
226 dce_conn
->auth_state
.auth_finished
= true;
227 dce_conn
->allow_request
= true;
231 /* We can't work without an existing gensec state */
232 if (!call
->conn
->auth_state
.gensec_security
) {
233 return NT_STATUS_INTERNAL_ERROR
;
236 if (call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
) {
237 dce_conn
->auth_state
.client_hdr_signing
= true;
238 want_header_signing
= true;
241 if (!lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","header signing", true)) {
242 want_header_signing
= false;
245 call
->_out_auth_info
= (struct dcerpc_auth
) {
246 .auth_type
= dce_conn
->auth_state
.auth_type
,
247 .auth_level
= dce_conn
->auth_state
.auth_level
,
248 .auth_context_id
= dce_conn
->auth_state
.auth_context_id
,
250 call
->out_auth_info
= &call
->_out_auth_info
;
252 status
= gensec_update_ev(dce_conn
->auth_state
.gensec_security
,
253 call
, call
->event_ctx
,
254 call
->in_auth_info
.credentials
,
255 &call
->out_auth_info
->credentials
);
257 if (NT_STATUS_IS_OK(status
)) {
258 status
= gensec_session_info(dce_conn
->auth_state
.gensec_security
,
260 &dce_conn
->auth_state
.session_info
);
261 if (!NT_STATUS_IS_OK(status
)) {
262 DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status
)));
265 dce_conn
->auth_state
.auth_finished
= true;
266 dce_conn
->allow_request
= true;
268 if (!gensec_have_feature(dce_conn
->auth_state
.gensec_security
,
269 GENSEC_FEATURE_SIGN_PKT_HEADER
))
271 want_header_signing
= false;
274 if (want_header_signing
) {
275 gensec_want_feature(dce_conn
->auth_state
.gensec_security
,
276 GENSEC_FEATURE_SIGN_PKT_HEADER
);
277 dce_conn
->auth_state
.hdr_signing
= true;
278 pkt
->pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
281 /* Now that we are authenticated, go back to the generic session key... */
282 dce_conn
->auth_state
.session_key
= dcesrv_generic_session_key
;
284 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
285 if (!gensec_have_feature(dce_conn
->auth_state
.gensec_security
,
286 GENSEC_FEATURE_SIGN_PKT_HEADER
))
288 want_header_signing
= false;
291 if (want_header_signing
) {
292 gensec_want_feature(dce_conn
->auth_state
.gensec_security
,
293 GENSEC_FEATURE_SIGN_PKT_HEADER
);
294 dce_conn
->auth_state
.hdr_signing
= true;
295 pkt
->pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
300 DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_ack: %s\n",
308 process the final stage of a auth request
310 bool dcesrv_auth_auth3(struct dcesrv_call_state
*call
)
312 struct ncacn_packet
*pkt
= &call
->pkt
;
313 struct dcesrv_connection
*dce_conn
= call
->conn
;
316 if (pkt
->auth_length
== 0) {
320 if (dce_conn
->auth_state
.auth_finished
) {
324 /* We can't work without an existing gensec state */
325 if (!dce_conn
->auth_state
.gensec_security
) {
329 status
= dcerpc_pull_auth_trailer(pkt
, call
, &pkt
->u
.auth3
.auth_info
,
330 &call
->in_auth_info
, NULL
, true);
331 if (!NT_STATUS_IS_OK(status
)) {
333 * Windows returns DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY
334 * instead of DCERPC_NCA_S_PROTO_ERROR.
336 call
->fault_code
= DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY
;
340 if (call
->in_auth_info
.auth_type
!= dce_conn
->auth_state
.auth_type
) {
344 if (call
->in_auth_info
.auth_level
!= dce_conn
->auth_state
.auth_level
) {
348 if (call
->in_auth_info
.auth_context_id
!= dce_conn
->auth_state
.auth_context_id
) {
352 call
->_out_auth_info
= (struct dcerpc_auth
) {
353 .auth_type
= dce_conn
->auth_state
.auth_type
,
354 .auth_level
= dce_conn
->auth_state
.auth_level
,
355 .auth_context_id
= dce_conn
->auth_state
.auth_context_id
,
357 call
->out_auth_info
= &call
->_out_auth_info
;
359 /* Pass the extra data we got from the client down to gensec for processing */
360 status
= gensec_update_ev(dce_conn
->auth_state
.gensec_security
,
361 call
, call
->event_ctx
,
362 call
->in_auth_info
.credentials
,
363 &call
->out_auth_info
->credentials
);
364 if (NT_STATUS_IS_OK(status
)) {
365 status
= gensec_session_info(dce_conn
->auth_state
.gensec_security
,
367 &dce_conn
->auth_state
.session_info
);
368 if (!NT_STATUS_IS_OK(status
)) {
369 DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status
)));
372 dce_conn
->auth_state
.auth_finished
= true;
373 dce_conn
->allow_request
= true;
375 /* Now that we are authenticated, go back to the generic session key... */
376 dce_conn
->auth_state
.session_key
= dcesrv_generic_session_key
;
378 if (call
->out_auth_info
->credentials
.length
!= 0) {
380 DEBUG(4, ("GENSEC produced output token (len=%u) at bind_auth3\n",
381 (unsigned)call
->out_auth_info
->credentials
.length
));
386 DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_auth3: %s\n",
393 parse any auth information from a dcerpc alter request
394 return false if we can't handle the auth request for some
395 reason (in which case we send a bind_nak (is this true for here?))
397 bool dcesrv_auth_alter(struct dcesrv_call_state
*call
)
399 struct ncacn_packet
*pkt
= &call
->pkt
;
400 struct dcesrv_connection
*dce_conn
= call
->conn
;
403 /* on a pure interface change there is no auth blob */
404 if (pkt
->auth_length
== 0) {
405 if (!dce_conn
->auth_state
.auth_finished
) {
411 if (dce_conn
->auth_state
.auth_finished
) {
412 call
->fault_code
= DCERPC_FAULT_ACCESS_DENIED
;
416 /* We can't work without an existing gensec state */
417 if (!dce_conn
->auth_state
.gensec_security
) {
421 status
= dcerpc_pull_auth_trailer(pkt
, call
, &pkt
->u
.alter
.auth_info
,
422 &call
->in_auth_info
, NULL
, true);
423 if (!NT_STATUS_IS_OK(status
)) {
424 call
->fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
428 if (call
->in_auth_info
.auth_type
== DCERPC_AUTH_TYPE_NONE
) {
429 call
->fault_code
= DCERPC_FAULT_ACCESS_DENIED
;
433 if (call
->in_auth_info
.auth_type
!= dce_conn
->auth_state
.auth_type
) {
437 if (call
->in_auth_info
.auth_level
!= dce_conn
->auth_state
.auth_level
) {
441 if (call
->in_auth_info
.auth_context_id
!= dce_conn
->auth_state
.auth_context_id
) {
449 add any auth information needed in a alter ack, and process the authentication
450 information found in the alter.
452 NTSTATUS
dcesrv_auth_alter_ack(struct dcesrv_call_state
*call
, struct ncacn_packet
*pkt
)
454 struct dcesrv_connection
*dce_conn
= call
->conn
;
457 /* on a pure interface change there is no auth_info structure
459 if (call
->pkt
.auth_length
== 0) {
463 if (!call
->conn
->auth_state
.gensec_security
) {
464 return NT_STATUS_INTERNAL_ERROR
;
467 call
->_out_auth_info
= (struct dcerpc_auth
) {
468 .auth_type
= dce_conn
->auth_state
.auth_type
,
469 .auth_level
= dce_conn
->auth_state
.auth_level
,
470 .auth_context_id
= dce_conn
->auth_state
.auth_context_id
,
472 call
->out_auth_info
= &call
->_out_auth_info
;
474 status
= gensec_update_ev(dce_conn
->auth_state
.gensec_security
,
475 call
, call
->event_ctx
,
476 call
->in_auth_info
.credentials
,
477 &call
->out_auth_info
->credentials
);
479 if (NT_STATUS_IS_OK(status
)) {
480 status
= gensec_session_info(dce_conn
->auth_state
.gensec_security
,
482 &dce_conn
->auth_state
.session_info
);
483 if (!NT_STATUS_IS_OK(status
)) {
484 DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status
)));
487 dce_conn
->auth_state
.auth_finished
= true;
488 dce_conn
->allow_request
= true;
490 /* Now that we are authenticated, got back to the generic session key... */
491 dce_conn
->auth_state
.session_key
= dcesrv_generic_session_key
;
493 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
497 DEBUG(4, ("GENSEC mech rejected the incoming authentication at auth alter_ack: %s\n",
503 check credentials on a packet
505 bool dcesrv_auth_pkt_pull(struct dcesrv_call_state
*call
,
506 DATA_BLOB
*full_packet
,
507 uint8_t required_flags
,
508 uint8_t optional_flags
,
509 uint8_t payload_offset
,
510 DATA_BLOB
*payload_and_verifier
)
512 struct ncacn_packet
*pkt
= &call
->pkt
;
513 struct dcesrv_connection
*dce_conn
= call
->conn
;
514 const struct dcerpc_auth tmp_auth
= {
515 .auth_type
= dce_conn
->auth_state
.auth_type
,
516 .auth_level
= dce_conn
->auth_state
.auth_level
,
517 .auth_context_id
= dce_conn
->auth_state
.auth_context_id
,
521 if (!dce_conn
->allow_request
) {
522 call
->fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
526 if (dce_conn
->auth_state
.auth_invalid
) {
530 status
= dcerpc_ncacn_pull_pkt_auth(&tmp_auth
,
531 dce_conn
->auth_state
.gensec_security
,
537 payload_and_verifier
,
540 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROTOCOL_ERROR
)) {
541 call
->fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
544 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL
)) {
545 call
->fault_code
= DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL
;
548 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
549 call
->fault_code
= DCERPC_FAULT_SEC_PKG_ERROR
;
552 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
553 call
->fault_code
= DCERPC_FAULT_ACCESS_DENIED
;
556 if (!NT_STATUS_IS_OK(status
)) {
564 push a signed or sealed dcerpc request packet into a blob
566 bool dcesrv_auth_pkt_push(struct dcesrv_call_state
*call
,
567 DATA_BLOB
*blob
, size_t sig_size
,
568 uint8_t payload_offset
,
569 const DATA_BLOB
*payload
,
570 const struct ncacn_packet
*pkt
)
572 struct dcesrv_connection
*dce_conn
= call
->conn
;
573 const struct dcerpc_auth tmp_auth
= {
574 .auth_type
= dce_conn
->auth_state
.auth_type
,
575 .auth_level
= dce_conn
->auth_state
.auth_level
,
576 .auth_context_id
= dce_conn
->auth_state
.auth_context_id
,
580 status
= dcerpc_ncacn_push_pkt_auth(&tmp_auth
,
581 dce_conn
->auth_state
.gensec_security
,
582 call
, blob
, sig_size
,
586 return NT_STATUS_IS_OK(status
);