CVE-2021-23192 librpc: Remove the gensec dependency from library dcerpc-binding
[samba.git] / librpc / rpc / dcesrv_auth.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc authentication code
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Stefan (metze) Metzmacher 2004
8
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.
13
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.
18
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/>.
21 */
22
23 #include "includes.h"
24 #include "librpc/rpc/dcesrv_core.h"
25 #include "librpc/rpc/dcesrv_core_proto.h"
26 #include "librpc/rpc/dcerpc_util.h"
27 #include "librpc/rpc/dcerpc_pkt_auth.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
34 static NTSTATUS dcesrv_auth_negotiate_hdr_signing(struct dcesrv_call_state *call,
35                                                   struct ncacn_packet *pkt)
36 {
37         struct dcesrv_connection *dce_conn = call->conn;
38         struct dcesrv_auth *a = NULL;
39
40         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
41                 return NT_STATUS_OK;
42         }
43
44         if (dce_conn->client_hdr_signing) {
45                 if (dce_conn->negotiated_hdr_signing && pkt != NULL) {
46                         pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
47                 }
48                 return NT_STATUS_OK;
49         }
50
51         dce_conn->client_hdr_signing = true;
52         dce_conn->negotiated_hdr_signing = dce_conn->support_hdr_signing;
53
54         if (!dce_conn->negotiated_hdr_signing) {
55                 return NT_STATUS_OK;
56         }
57
58         if (pkt != NULL) {
59                 pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
60         }
61
62         a = call->conn->default_auth_state;
63         if (a->gensec_security != NULL) {
64                 gensec_want_feature(a->gensec_security,
65                                     GENSEC_FEATURE_SIGN_PKT_HEADER);
66         }
67
68         for (a = call->conn->auth_states; a != NULL; a = a->next) {
69                 if (a->gensec_security == NULL) {
70                         continue;
71                 }
72
73                 gensec_want_feature(a->gensec_security,
74                                     GENSEC_FEATURE_SIGN_PKT_HEADER);
75         }
76
77         return NT_STATUS_OK;
78 }
79
80 static bool dcesrv_auth_prepare_gensec(struct dcesrv_call_state *call)
81 {
82         struct dcesrv_connection *dce_conn = call->conn;
83         struct dcesrv_auth *auth = call->auth_state;
84         NTSTATUS status;
85
86         if (auth->auth_started) {
87                 return false;
88         }
89
90         auth->auth_started = true;
91
92         if (auth->auth_invalid) {
93                 return false;
94         }
95
96         if (auth->auth_finished) {
97                 return false;
98         }
99
100         if (auth->gensec_security != NULL) {
101                 return false;
102         }
103
104         switch (call->in_auth_info.auth_level) {
105         case DCERPC_AUTH_LEVEL_CONNECT:
106         case DCERPC_AUTH_LEVEL_CALL:
107         case DCERPC_AUTH_LEVEL_PACKET:
108         case DCERPC_AUTH_LEVEL_INTEGRITY:
109         case DCERPC_AUTH_LEVEL_PRIVACY:
110                 /*
111                  * We evaluate auth_type only if auth_level was valid
112                  */
113                 break;
114         default:
115                 /*
116                  * Setting DCERPC_AUTH_LEVEL_NONE,
117                  * gives the caller the reject_reason
118                  * as auth_context_id.
119                  *
120                  * Note: DCERPC_AUTH_LEVEL_NONE == 1
121                  */
122                 auth->auth_type = DCERPC_AUTH_TYPE_NONE;
123                 auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
124                 auth->auth_context_id = DCERPC_BIND_NAK_REASON_NOT_SPECIFIED;
125                 return false;
126         }
127
128         auth->auth_type = call->in_auth_info.auth_type;
129         auth->auth_level = call->in_auth_info.auth_level;
130         auth->auth_context_id = call->in_auth_info.auth_context_id;
131
132         status = call->conn->dce_ctx->callbacks.auth.gensec_prepare(auth,
133                                                 call,
134                                                 &auth->gensec_security);
135         if (!NT_STATUS_IS_OK(status)) {
136                 DEBUG(1, ("Failed to call samba_server_gensec_start %s\n",
137                           nt_errstr(status)));
138                 return false;
139         }
140
141         /*
142          * We have to call this because we set the target_service for
143          * Kerberos to NULL above, and in any case we wish to log a
144          * more specific service target.
145          *
146          */
147         status = gensec_set_target_service_description(auth->gensec_security,
148                                                        "DCE/RPC");
149         if (!NT_STATUS_IS_OK(status)) {
150                 DEBUG(1, ("Failed to call gensec_set_target_service_description %s\n",
151                           nt_errstr(status)));
152                 return false;
153         }
154
155         if (call->conn->remote_address != NULL) {
156                 status = gensec_set_remote_address(auth->gensec_security,
157                                                 call->conn->remote_address);
158                 if (!NT_STATUS_IS_OK(status)) {
159                         DEBUG(1, ("Failed to call gensec_set_remote_address() %s\n",
160                                   nt_errstr(status)));
161                         return false;
162                 }
163         }
164
165         if (call->conn->local_address != NULL) {
166                 status = gensec_set_local_address(auth->gensec_security,
167                                                   call->conn->local_address);
168                 if (!NT_STATUS_IS_OK(status)) {
169                         DEBUG(1, ("Failed to call gensec_set_local_address() %s\n",
170                                   nt_errstr(status)));
171                         return false;
172                 }
173         }
174
175         status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_type,
176                                                auth->auth_level);
177         if (!NT_STATUS_IS_OK(status)) {
178                 const char *backend_name =
179                         gensec_get_name_by_authtype(auth->gensec_security,
180                                                     auth->auth_type);
181
182                 DEBUG(3, ("Failed to start GENSEC mechanism for DCERPC server: "
183                           "auth_type=%d (%s), auth_level=%d: %s\n",
184                           (int)auth->auth_type, backend_name,
185                           (int)auth->auth_level,
186                           nt_errstr(status)));
187
188                 /*
189                  * Setting DCERPC_AUTH_LEVEL_NONE,
190                  * gives the caller the reject_reason
191                  * as auth_context_id.
192                  *
193                  * Note: DCERPC_AUTH_LEVEL_NONE == 1
194                  */
195                 auth->auth_type = DCERPC_AUTH_TYPE_NONE;
196                 auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
197                 if (backend_name != NULL) {
198                         auth->auth_context_id =
199                                 DCERPC_BIND_NAK_REASON_INVALID_CHECKSUM;
200                 } else {
201                         auth->auth_context_id =
202                                 DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE;
203                 }
204                 return false;
205         }
206
207         if (dce_conn->negotiated_hdr_signing) {
208                 gensec_want_feature(auth->gensec_security,
209                                     GENSEC_FEATURE_SIGN_PKT_HEADER);
210         }
211
212         return true;
213 }
214
215 static void dcesrv_default_auth_state_finish_bind(struct dcesrv_call_state *call)
216 {
217         SMB_ASSERT(call->pkt.ptype == DCERPC_PKT_BIND);
218
219         if (call->auth_state == call->conn->default_auth_state) {
220                 return;
221         }
222
223         if (call->conn->default_auth_state->auth_started) {
224                 return;
225         }
226
227         if (call->conn->default_auth_state->auth_invalid) {
228                 return;
229         }
230
231         call->conn->default_auth_state->auth_type = DCERPC_AUTH_TYPE_NONE;
232         call->conn->default_auth_state->auth_level = DCERPC_AUTH_LEVEL_NONE;
233         call->conn->default_auth_state->auth_context_id = 0;
234         call->conn->default_auth_state->auth_started = true;
235         call->conn->default_auth_state->auth_finished = true;
236
237         /*
238          *
239          * We defer log_successful_dcesrv_authz_event()
240          * to dcesrv_default_auth_state_prepare_request()
241          *
242          * As we don't want to trigger authz_events
243          * just for alter_context requests without authentication
244          */
245 }
246
247 void dcesrv_default_auth_state_prepare_request(struct dcesrv_call_state *call)
248 {
249         struct dcesrv_connection *dce_conn = call->conn;
250         struct dcesrv_auth *auth = call->auth_state;
251
252         if (auth->auth_audited) {
253                 return;
254         }
255
256         if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
257                 return;
258         }
259
260         if (auth != dce_conn->default_auth_state) {
261                 return;
262         }
263
264         if (auth->auth_invalid) {
265                 return;
266         }
267
268         if (!auth->auth_finished) {
269                 return;
270         }
271
272         if (!call->conn->dce_ctx->callbacks.log.successful_authz) {
273                 return;
274         }
275
276         call->conn->dce_ctx->callbacks.log.successful_authz(call);
277 }
278
279 /*
280   parse any auth information from a dcerpc bind request
281   return false if we can't handle the auth request for some
282   reason (in which case we send a bind_nak)
283 */
284 bool dcesrv_auth_bind(struct dcesrv_call_state *call)
285 {
286         struct ncacn_packet *pkt = &call->pkt;
287         struct dcesrv_auth *auth = call->auth_state;
288         NTSTATUS status;
289
290         if (pkt->auth_length == 0) {
291                 auth->auth_type = DCERPC_AUTH_TYPE_NONE;
292                 auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
293                 auth->auth_context_id = 0;
294                 auth->auth_started = true;
295
296                 if (call->conn->dce_ctx->callbacks.log.successful_authz) {
297                         call->conn->dce_ctx->callbacks.log.successful_authz(call);
298                 }
299
300                 return true;
301         }
302
303         status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info,
304                                           &call->in_auth_info,
305                                           NULL, true);
306         if (!NT_STATUS_IS_OK(status)) {
307                 /*
308                  * Setting DCERPC_AUTH_LEVEL_NONE,
309                  * gives the caller the reject_reason
310                  * as auth_context_id.
311                  *
312                  * Note: DCERPC_AUTH_LEVEL_NONE == 1
313                  */
314                 auth->auth_type = DCERPC_AUTH_TYPE_NONE;
315                 auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
316                 auth->auth_context_id =
317                         DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED;
318                 return false;
319         }
320
321         return dcesrv_auth_prepare_gensec(call);
322 }
323
324 NTSTATUS dcesrv_auth_complete(struct dcesrv_call_state *call, NTSTATUS status)
325 {
326         struct dcesrv_auth *auth = call->auth_state;
327         const char *pdu = "<unknown>";
328
329         switch (call->pkt.ptype) {
330         case DCERPC_PKT_BIND:
331                 pdu = "BIND";
332                 break;
333         case DCERPC_PKT_ALTER:
334                 pdu = "ALTER";
335                 break;
336         case DCERPC_PKT_AUTH3:
337                 pdu = "AUTH3";
338                 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
339                         DEBUG(4, ("GENSEC not finished at at %s\n", pdu));
340                         return NT_STATUS_RPC_SEC_PKG_ERROR;
341                 }
342                 break;
343         default:
344                 return NT_STATUS_INTERNAL_ERROR;
345         }
346
347         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
348                 return NT_STATUS_OK;
349         }
350
351         if (!NT_STATUS_IS_OK(status)) {
352                 DEBUG(4, ("GENSEC mech rejected the incoming authentication "
353                           "at %s: %s\n", pdu, nt_errstr(status)));
354                 return status;
355         }
356
357         status = gensec_session_info(auth->gensec_security,
358                                      auth,
359                                      &auth->session_info);
360         if (!NT_STATUS_IS_OK(status)) {
361                 DEBUG(1, ("Failed to establish session_info: %s\n",
362                           nt_errstr(status)));
363                 return status;
364         }
365         auth->auth_finished = true;
366
367         if (auth->auth_level == DCERPC_AUTH_LEVEL_CONNECT &&
368             !call->conn->got_explicit_auth_level_connect)
369         {
370                 call->conn->default_auth_level_connect = auth;
371         }
372
373         if (call->pkt.ptype != DCERPC_PKT_AUTH3) {
374                 return NT_STATUS_OK;
375         }
376
377         if (call->out_auth_info->credentials.length != 0) {
378                 DEBUG(4, ("GENSEC produced output token (len=%zu) at %s\n",
379                           call->out_auth_info->credentials.length, pdu));
380                 return NT_STATUS_RPC_SEC_PKG_ERROR;
381         }
382
383         return NT_STATUS_OK;
384 }
385
386 /*
387   add any auth information needed in a bind ack, and process the authentication
388   information found in the bind.
389 */
390 NTSTATUS dcesrv_auth_prepare_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
391 {
392         struct dcesrv_connection *dce_conn = call->conn;
393         struct dcesrv_auth *auth = call->auth_state;
394         NTSTATUS status;
395
396         status = dcesrv_auth_negotiate_hdr_signing(call, pkt);
397         if (!NT_STATUS_IS_OK(status)) {
398                 return status;
399         }
400
401         dce_conn->allow_alter = true;
402         dcesrv_default_auth_state_finish_bind(call);
403
404         if (call->pkt.auth_length == 0) {
405                 auth->auth_finished = true;
406                 return NT_STATUS_OK;
407         }
408
409         /* We can't work without an existing gensec state */
410         if (auth->gensec_security == NULL) {
411                 return NT_STATUS_INTERNAL_ERROR;
412         }
413
414         call->_out_auth_info = (struct dcerpc_auth) {
415                 .auth_type = auth->auth_type,
416                 .auth_level = auth->auth_level,
417                 .auth_context_id = auth->auth_context_id,
418         };
419         call->out_auth_info = &call->_out_auth_info;
420
421         return NT_STATUS_OK;
422 }
423
424 /*
425   process the final stage of a auth request
426 */
427 bool dcesrv_auth_prepare_auth3(struct dcesrv_call_state *call)
428 {
429         struct ncacn_packet *pkt = &call->pkt;
430         struct dcesrv_auth *auth = call->auth_state;
431         NTSTATUS status;
432
433         if (pkt->auth_length == 0) {
434                 return false;
435         }
436
437         if (auth->auth_finished) {
438                 return false;
439         }
440
441         /* We can't work without an existing gensec state */
442         if (auth->gensec_security == NULL) {
443                 return false;
444         }
445
446         status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info,
447                                           &call->in_auth_info, NULL, true);
448         if (!NT_STATUS_IS_OK(status)) {
449                 /*
450                  * Windows returns DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY
451                  * instead of DCERPC_NCA_S_PROTO_ERROR.
452                  */
453                 call->fault_code = DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY;
454                 return false;
455         }
456
457         if (call->in_auth_info.auth_type != auth->auth_type) {
458                 return false;
459         }
460
461         if (call->in_auth_info.auth_level != auth->auth_level) {
462                 return false;
463         }
464
465         if (call->in_auth_info.auth_context_id != auth->auth_context_id) {
466                 return false;
467         }
468
469         call->_out_auth_info = (struct dcerpc_auth) {
470                 .auth_type = auth->auth_type,
471                 .auth_level = auth->auth_level,
472                 .auth_context_id = auth->auth_context_id,
473         };
474         call->out_auth_info = &call->_out_auth_info;
475
476         return true;
477 }
478
479 /*
480   parse any auth information from a dcerpc alter request
481   return false if we can't handle the auth request for some
482   reason (in which case we send a bind_nak (is this true for here?))
483 */
484 bool dcesrv_auth_alter(struct dcesrv_call_state *call)
485 {
486         struct ncacn_packet *pkt = &call->pkt;
487         struct dcesrv_auth *auth = call->auth_state;
488         NTSTATUS status;
489
490         /* on a pure interface change there is no auth blob */
491         if (pkt->auth_length == 0) {
492                 if (!auth->auth_finished) {
493                         return false;
494                 }
495                 return true;
496         }
497
498         if (auth->auth_finished) {
499                 call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
500                 return false;
501         }
502
503         status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.alter.auth_info,
504                                           &call->in_auth_info, NULL, true);
505         if (!NT_STATUS_IS_OK(status)) {
506                 call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
507                 return false;
508         }
509
510         if (!auth->auth_started) {
511                 bool ok;
512
513                 ok = dcesrv_auth_prepare_gensec(call);
514                 if (!ok) {
515                         call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
516                         return false;
517                 }
518
519                 return true;
520         }
521
522         if (call->in_auth_info.auth_type == DCERPC_AUTH_TYPE_NONE) {
523                 call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
524                 return false;
525         }
526
527         if (call->in_auth_info.auth_type != auth->auth_type) {
528                 return false;
529         }
530
531         if (call->in_auth_info.auth_level != auth->auth_level) {
532                 return false;
533         }
534
535         if (call->in_auth_info.auth_context_id != auth->auth_context_id) {
536                 return false;
537         }
538
539         return true;
540 }
541
542 /*
543   add any auth information needed in a alter ack, and process the authentication
544   information found in the alter.
545 */
546 NTSTATUS dcesrv_auth_prepare_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
547 {
548         struct dcesrv_auth *auth = call->auth_state;
549         NTSTATUS status;
550
551         status = dcesrv_auth_negotiate_hdr_signing(call, pkt);
552         if (!NT_STATUS_IS_OK(status)) {
553                 return status;
554         }
555
556         /* on a pure interface change there is no auth_info structure
557            setup */
558         if (call->pkt.auth_length == 0) {
559                 return NT_STATUS_OK;
560         }
561
562         if (auth->gensec_security == NULL) {
563                 return NT_STATUS_INTERNAL_ERROR;
564         }
565
566         call->_out_auth_info = (struct dcerpc_auth) {
567                 .auth_type = auth->auth_type,
568                 .auth_level = auth->auth_level,
569                 .auth_context_id = auth->auth_context_id,
570         };
571         call->out_auth_info = &call->_out_auth_info;
572
573         return NT_STATUS_OK;
574 }
575
576 /*
577   check credentials on a packet
578 */
579 bool dcesrv_auth_pkt_pull(struct dcesrv_call_state *call,
580                           DATA_BLOB *full_packet,
581                           uint8_t required_flags,
582                           uint8_t optional_flags,
583                           uint8_t payload_offset,
584                           DATA_BLOB *payload_and_verifier)
585 {
586         struct ncacn_packet *pkt = &call->pkt;
587         struct dcesrv_auth *auth = call->auth_state;
588         const struct dcerpc_auth tmp_auth = {
589                 .auth_type = auth->auth_type,
590                 .auth_level = auth->auth_level,
591                 .auth_context_id = auth->auth_context_id,
592         };
593         NTSTATUS status;
594
595         if (!auth->auth_started) {
596                 return false;
597         }
598
599         if (!auth->auth_finished) {
600                 call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
601                 return false;
602         }
603
604         if (auth->auth_invalid) {
605                 return false;
606         }
607
608         status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
609                                             auth->gensec_security,
610                                             call,
611                                             pkt->ptype,
612                                             required_flags,
613                                             optional_flags,
614                                             payload_offset,
615                                             payload_and_verifier,
616                                             full_packet,
617                                             pkt);
618         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
619                 call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
620                 return false;
621         }
622         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL)) {
623                 call->fault_code = DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL;
624                 return false;
625         }
626         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
627                 call->fault_code = DCERPC_FAULT_SEC_PKG_ERROR;
628                 return false;
629         }
630         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
631                 call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
632                 return false;
633         }
634         if (!NT_STATUS_IS_OK(status)) {
635                 return false;
636         }
637
638         return true;
639 }
640
641 /*
642    push a signed or sealed dcerpc request packet into a blob
643 */
644 bool dcesrv_auth_pkt_push(struct dcesrv_call_state *call,
645                           DATA_BLOB *blob, size_t sig_size,
646                           uint8_t payload_offset,
647                           const DATA_BLOB *payload,
648                           const struct ncacn_packet *pkt)
649 {
650         struct dcesrv_auth *auth = call->auth_state;
651         const struct dcerpc_auth tmp_auth = {
652                 .auth_type = auth->auth_type,
653                 .auth_level = auth->auth_level,
654                 .auth_context_id = auth->auth_context_id,
655         };
656         NTSTATUS status;
657
658         status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
659                                             auth->gensec_security,
660                                             call, blob, sig_size,
661                                             payload_offset,
662                                             payload,
663                                             pkt);
664         return NT_STATUS_IS_OK(status);
665 }