LCOV - code coverage report
Current view: top level - librpc/rpc - dcerpc_pkt_auth.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 166 230 72.2 %
Date: 2024-02-28 12:06:22 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    raw dcerpc operations
       4             : 
       5             :    Copyright (C) Andrew Tridgell 2003-2005
       6             :    Copyright (C) Jelmer Vernooij 2004-2005
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "replace.h"
      23             : #include "system/network.h"
      24             : #include <tevent.h>
      25             : #include "lib/util/talloc_stack.h"
      26             : #include "lib/util/debug.h"
      27             : #include "lib/util/byteorder.h"
      28             : #include "lib/util/samba_util.h"
      29             : #include "librpc/rpc/dcerpc.h"
      30             : #include "librpc/rpc/dcerpc_util.h"
      31             : #include "librpc/rpc/dcerpc_pkt_auth.h"
      32             : #include "librpc/gen_ndr/ndr_dcerpc.h"
      33             : #include "rpc_common.h"
      34             : #include "lib/util/bitmap.h"
      35             : #include "auth/gensec/gensec.h"
      36             : #include "lib/util/mkdir_p.h"
      37             : #include "lib/crypto/gnutls_helpers.h"
      38             : #include <gnutls/crypto.h>
      39             : 
      40     1450304 : NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
      41             :                                     struct gensec_security *gensec,
      42             :                                     bool check_pkt_auth_fields,
      43             :                                     TALLOC_CTX *mem_ctx,
      44             :                                     enum dcerpc_pkt_type ptype,
      45             :                                     uint8_t required_flags,
      46             :                                     uint8_t optional_flags,
      47             :                                     uint8_t payload_offset,
      48             :                                     DATA_BLOB *payload_and_verifier,
      49             :                                     DATA_BLOB *raw_packet,
      50             :                                     const struct ncacn_packet *pkt)
      51             : {
      52       14116 :         NTSTATUS status;
      53       14116 :         struct dcerpc_auth auth;
      54       14116 :         uint32_t auth_length;
      55             : 
      56     1450304 :         if (auth_state == NULL) {
      57           0 :                 return NT_STATUS_INTERNAL_ERROR;
      58             :         }
      59             : 
      60     1450304 :         status = dcerpc_verify_ncacn_packet_header(pkt, ptype,
      61             :                                         payload_and_verifier->length,
      62             :                                         required_flags, optional_flags);
      63     1450304 :         if (!NT_STATUS_IS_OK(status)) {
      64           0 :                 return status;
      65             :         }
      66             : 
      67     1450304 :         switch (auth_state->auth_level) {
      68      478940 :         case DCERPC_AUTH_LEVEL_PRIVACY:
      69             :         case DCERPC_AUTH_LEVEL_INTEGRITY:
      70             :         case DCERPC_AUTH_LEVEL_PACKET:
      71      478940 :                 break;
      72             : 
      73        3118 :         case DCERPC_AUTH_LEVEL_CONNECT:
      74        3118 :                 if (pkt->auth_length != 0) {
      75          49 :                         break;
      76             :                 }
      77      957227 :                 return NT_STATUS_OK;
      78      961461 :         case DCERPC_AUTH_LEVEL_NONE:
      79      961461 :                 if (pkt->auth_length != 0) {
      80           0 :                         return NT_STATUS_ACCESS_DENIED;
      81             :                 }
      82      961461 :                 return NT_STATUS_OK;
      83             : 
      84           0 :         default:
      85           0 :                 return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
      86             :         }
      87             : 
      88      485774 :         if (pkt->auth_length == 0) {
      89          12 :                 return NT_STATUS_RPC_PROTOCOL_ERROR;
      90             :         }
      91             : 
      92      485762 :         if (gensec == NULL) {
      93           0 :                 return NT_STATUS_INTERNAL_ERROR;
      94             :         }
      95             : 
      96      485762 :         status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
      97             :                                           payload_and_verifier,
      98             :                                           &auth, &auth_length, false);
      99      485762 :         if (!NT_STATUS_IS_OK(status)) {
     100           0 :                 return status;
     101             :         }
     102             : 
     103      485762 :         if (payload_and_verifier->length < auth_length) {
     104             :                 /*
     105             :                  * should be checked in dcerpc_pull_auth_trailer()
     106             :                  */
     107           0 :                 return NT_STATUS_INTERNAL_ERROR;
     108             :         }
     109             : 
     110      485762 :         payload_and_verifier->length -= auth_length;
     111             : 
     112      485762 :         if (payload_and_verifier->length < auth.auth_pad_length) {
     113             :                 /*
     114             :                  * should be checked in dcerpc_pull_auth_trailer()
     115             :                  */
     116           0 :                 return NT_STATUS_INTERNAL_ERROR;
     117             :         }
     118             : 
     119      485762 :         if (check_pkt_auth_fields) {
     120      476939 :                 if (auth.auth_type != auth_state->auth_type) {
     121           0 :                         return NT_STATUS_ACCESS_DENIED;
     122             :                 }
     123             : 
     124      476939 :                 if (auth.auth_level != auth_state->auth_level) {
     125           0 :                         return NT_STATUS_ACCESS_DENIED;
     126             :                 }
     127             : 
     128      476939 :                 if (auth.auth_context_id != auth_state->auth_context_id) {
     129           0 :                         return NT_STATUS_ACCESS_DENIED;
     130             :                 }
     131             :         }
     132             : 
     133             :         /* check signature or unseal the packet */
     134      485762 :         switch (auth_state->auth_level) {
     135      398615 :         case DCERPC_AUTH_LEVEL_PRIVACY:
     136      402747 :                 status = gensec_unseal_packet(gensec,
     137      394483 :                                               raw_packet->data + payload_offset,
     138             :                                               payload_and_verifier->length,
     139      398615 :                                               raw_packet->data,
     140      398615 :                                               raw_packet->length -
     141      398615 :                                               auth.credentials.length,
     142             :                                               &auth.credentials);
     143      398615 :                 if (!NT_STATUS_IS_OK(status)) {
     144           0 :                         return NT_STATUS_RPC_SEC_PKG_ERROR;
     145             :                 }
     146      405400 :                 memcpy(payload_and_verifier->data,
     147      398615 :                        raw_packet->data + payload_offset,
     148             :                        payload_and_verifier->length);
     149      394483 :                 break;
     150             : 
     151       87098 :         case DCERPC_AUTH_LEVEL_INTEGRITY:
     152             :         case DCERPC_AUTH_LEVEL_PACKET:
     153       89751 :                 status = gensec_check_packet(gensec,
     154       87098 :                                              payload_and_verifier->data,
     155             :                                              payload_and_verifier->length,
     156       87098 :                                              raw_packet->data,
     157       87098 :                                              raw_packet->length -
     158       87098 :                                              auth.credentials.length,
     159             :                                              &auth.credentials);
     160       87098 :                 if (!NT_STATUS_IS_OK(status)) {
     161          21 :                         return NT_STATUS_RPC_SEC_PKG_ERROR;
     162             :                 }
     163       84424 :                 break;
     164             : 
     165          49 :         case DCERPC_AUTH_LEVEL_CONNECT:
     166             :                 /* for now we ignore possible signatures here */
     167          49 :                 break;
     168             : 
     169           0 :         default:
     170           0 :                 return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
     171             :         }
     172             : 
     173             :         /*
     174             :          * remove the indicated amount of padding
     175             :          *
     176             :          * A possible overflow is checked above.
     177             :          */
     178      485741 :         payload_and_verifier->length -= auth.auth_pad_length;
     179             : 
     180      485741 :         return NT_STATUS_OK;
     181             : }
     182             : 
     183     1447707 : NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
     184             :                                     struct gensec_security *gensec,
     185             :                                     TALLOC_CTX *mem_ctx,
     186             :                                     DATA_BLOB *raw_packet,
     187             :                                     size_t sig_size,
     188             :                                     uint8_t payload_offset,
     189             :                                     const DATA_BLOB *payload,
     190             :                                     const struct ncacn_packet *pkt)
     191             : {
     192     1447707 :         TALLOC_CTX *frame = talloc_stackframe();
     193       14119 :         NTSTATUS status;
     194       14119 :         enum ndr_err_code ndr_err;
     195     1447707 :         struct ndr_push *ndr = NULL;
     196       14119 :         uint32_t payload_length;
     197       14119 :         uint32_t whole_length;
     198     1447707 :         DATA_BLOB blob = data_blob_null;
     199     1447707 :         DATA_BLOB sig = data_blob_null;
     200       14119 :         struct dcerpc_auth _out_auth_info;
     201     1447707 :         struct dcerpc_auth *out_auth_info = NULL;
     202             : 
     203     1447707 :         *raw_packet = data_blob_null;
     204             : 
     205     1447707 :         if (auth_state == NULL) {
     206           0 :                 TALLOC_FREE(frame);
     207           0 :                 return NT_STATUS_INTERNAL_ERROR;
     208             :         }
     209             : 
     210     1447707 :         switch (auth_state->auth_level) {
     211      485650 :         case DCERPC_AUTH_LEVEL_PRIVACY:
     212             :         case DCERPC_AUTH_LEVEL_INTEGRITY:
     213             :         case DCERPC_AUTH_LEVEL_PACKET:
     214      485650 :                 if (sig_size == 0) {
     215           0 :                         TALLOC_FREE(frame);
     216           0 :                         return NT_STATUS_INTERNAL_ERROR;
     217             :                 }
     218             : 
     219      485650 :                 if (gensec == NULL) {
     220           0 :                         TALLOC_FREE(frame);
     221           0 :                         return NT_STATUS_INTERNAL_ERROR;
     222             :                 }
     223             : 
     224      485650 :                 _out_auth_info = (struct dcerpc_auth) {
     225      485650 :                         .auth_type = auth_state->auth_type,
     226      478864 :                         .auth_level = auth_state->auth_level,
     227      485650 :                         .auth_context_id = auth_state->auth_context_id,
     228             :                 };
     229      485650 :                 out_auth_info = &_out_auth_info;
     230      485650 :                 break;
     231             : 
     232        3088 :         case DCERPC_AUTH_LEVEL_CONNECT:
     233             :                 /*
     234             :                  * TODO: let the gensec mech decide if it wants to generate a
     235             :                  *       signature that might be needed for schannel...
     236             :                  */
     237        3088 :                 if (sig_size != 0) {
     238           0 :                         TALLOC_FREE(frame);
     239           0 :                         return NT_STATUS_INTERNAL_ERROR;
     240             :                 }
     241             : 
     242        3088 :                 if (gensec == NULL) {
     243           0 :                         TALLOC_FREE(frame);
     244           0 :                         return NT_STATUS_INTERNAL_ERROR;
     245             :                 }
     246        3060 :                 break;
     247             : 
     248      958969 :         case DCERPC_AUTH_LEVEL_NONE:
     249      958969 :                 if (sig_size != 0) {
     250           0 :                         TALLOC_FREE(frame);
     251           0 :                         return NT_STATUS_INTERNAL_ERROR;
     252             :                 }
     253      951664 :                 break;
     254             : 
     255           0 :         default:
     256           0 :                 TALLOC_FREE(frame);
     257           0 :                 return NT_STATUS_INTERNAL_ERROR;
     258             :         }
     259             : 
     260     1447707 :         ndr = ndr_push_init_ctx(frame);
     261     1447707 :         if (ndr == NULL) {
     262           0 :                 TALLOC_FREE(frame);
     263           0 :                 return NT_STATUS_NO_MEMORY;
     264             :         }
     265             : 
     266     1447707 :         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
     267     1447707 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     268           0 :                 TALLOC_FREE(frame);
     269           0 :                 return ndr_map_error2ntstatus(ndr_err);
     270             :         }
     271             : 
     272     1447707 :         if (out_auth_info != NULL) {
     273             :                 /*
     274             :                  * pad to 16 byte multiple in the payload portion of the
     275             :                  * packet. This matches what w2k3 does. Note that we can't use
     276             :                  * ndr_push_align() as that is relative to the start of the
     277             :                  * whole packet, whereas w2k8 wants it relative to the start
     278             :                  * of the stub.
     279             :                  */
     280      347449 :                 out_auth_info->auth_pad_length =
     281      485650 :                         DCERPC_AUTH_PAD_LENGTH(payload->length);
     282      485650 :                 ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length);
     283      485650 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     284           0 :                         TALLOC_FREE(frame);
     285           0 :                         return ndr_map_error2ntstatus(ndr_err);
     286             :                 }
     287             : 
     288      485650 :                 payload_length = payload->length +
     289      485650 :                         out_auth_info->auth_pad_length;
     290             : 
     291      485650 :                 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
     292             :                                                out_auth_info);
     293      485650 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     294           0 :                         TALLOC_FREE(frame);
     295           0 :                         return ndr_map_error2ntstatus(ndr_err);
     296             :                 }
     297             : 
     298      485650 :                 whole_length = ndr->offset;
     299             : 
     300      485650 :                 ndr_err = ndr_push_zero(ndr, sig_size);
     301      485650 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     302           0 :                         TALLOC_FREE(frame);
     303           0 :                         return ndr_map_error2ntstatus(ndr_err);
     304             :                 }
     305             :         } else {
     306      962057 :                 payload_length = payload->length;
     307      962057 :                 whole_length = ndr->offset;
     308             :         }
     309             : 
     310             :         /* extract the whole packet as a blob */
     311     1447707 :         blob = ndr_push_blob(ndr);
     312             : 
     313             :         /*
     314             :          * Setup the frag and auth length in the packet buffer.
     315             :          * This is needed if the GENSEC mech does AEAD signing
     316             :          * of the packet headers. The signature itself will be
     317             :          * appended later.
     318             :          */
     319     1447707 :         dcerpc_set_frag_length(&blob, blob.length);
     320     1447707 :         dcerpc_set_auth_length(&blob, sig_size);
     321             : 
     322             :         /* sign or seal the packet */
     323     1447707 :         switch (auth_state->auth_level) {
     324      398670 :         case DCERPC_AUTH_LEVEL_PRIVACY:
     325      402803 :                 status = gensec_seal_packet(gensec,
     326             :                                             frame,
     327      394537 :                                             blob.data + payload_offset,
     328             :                                             payload_length,
     329      398670 :                                             blob.data,
     330             :                                             whole_length,
     331             :                                             &sig);
     332      398670 :                 if (!NT_STATUS_IS_OK(status)) {
     333           0 :                         TALLOC_FREE(frame);
     334           0 :                         return status;
     335             :                 }
     336      394537 :                 break;
     337             : 
     338       86980 :         case DCERPC_AUTH_LEVEL_INTEGRITY:
     339             :         case DCERPC_AUTH_LEVEL_PACKET:
     340       89633 :                 status = gensec_sign_packet(gensec,
     341             :                                             frame,
     342       86980 :                                             blob.data + payload_offset,
     343             :                                             payload_length,
     344       86980 :                                             blob.data,
     345             :                                             whole_length,
     346             :                                             &sig);
     347       86980 :                 if (!NT_STATUS_IS_OK(status)) {
     348           0 :                         TALLOC_FREE(frame);
     349           0 :                         return status;
     350             :                 }
     351       84327 :                 break;
     352             : 
     353      954724 :         case DCERPC_AUTH_LEVEL_CONNECT:
     354             :         case DCERPC_AUTH_LEVEL_NONE:
     355      954724 :                 break;
     356             : 
     357           0 :         default:
     358           0 :                 TALLOC_FREE(frame);
     359           0 :                 return NT_STATUS_INTERNAL_ERROR;
     360             :         }
     361             : 
     362     1447707 :         if (sig.length != sig_size) {
     363           0 :                 TALLOC_FREE(frame);
     364           0 :                 return NT_STATUS_RPC_SEC_PKG_ERROR;
     365             :         }
     366             : 
     367     1447707 :         if (sig_size != 0) {
     368      485650 :                 memcpy(blob.data + whole_length, sig.data, sig_size);
     369             :         }
     370             : 
     371     1447707 :         *raw_packet = blob;
     372     1447707 :         talloc_steal(mem_ctx, raw_packet->data);
     373     1447707 :         TALLOC_FREE(frame);
     374     1447707 :         return NT_STATUS_OK;
     375             : }
     376             : 
     377             : #ifdef DEVELOPER
     378             : 
     379             : /*
     380             :  * Save valid, well-formed DCE/RPC stubs to use as a seed for
     381             :  * ndr_fuzz_X
     382             :  */
     383     1695786 : void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx,
     384             :                                DATA_BLOB raw_blob,
     385             :                                const char *dump_dir,
     386             :                                const char *iface_name,
     387             :                                ndr_flags_type flags,
     388             :                                int opnum,
     389             :                                bool ndr64)
     390             : {
     391     1695786 :         char *fname = NULL;
     392     1695786 :         const char *sub_dir = NULL;
     393     1695786 :         TALLOC_CTX *temp_ctx = talloc_new(mem_ctx);
     394       13980 :         DATA_BLOB blob;
     395       13980 :         int ret, rc;
     396       13980 :         uint8_t digest[20];
     397       13980 :         DATA_BLOB digest_blob;
     398       13980 :         char *digest_hex;
     399     1695786 :         uint16_t fuzz_flags = 0;
     400             : 
     401             :         /*
     402             :          * We want to save the 'stub' in a per-pipe subdirectory, with
     403             :          * the ndr_fuzz_X header 4 byte header. For the sake of
     404             :          * convenience (this is a developer only function), we mkdir
     405             :          * -p the sub-directories when they are needed.
     406             :          */
     407             : 
     408     1695786 :         if (dump_dir == NULL) {
     409      933668 :                 return;
     410             :         }
     411             : 
     412      762118 :         temp_ctx = talloc_stackframe();
     413             : 
     414      762118 :         sub_dir = talloc_asprintf(temp_ctx, "%s/%s",
     415             :                                   dump_dir,
     416             :                                   iface_name);
     417      762118 :         if (sub_dir == NULL) {
     418           0 :                 talloc_free(temp_ctx);
     419           0 :                 return;
     420             :         }
     421      762118 :         ret = mkdir_p(sub_dir, 0755);
     422      762118 :         if (ret && errno != EEXIST) {
     423           0 :                 DBG_ERR("could not create %s\n", sub_dir);
     424           0 :                 talloc_free(temp_ctx);
     425           0 :                 return;
     426             :         }
     427             : 
     428      762118 :         blob.length = raw_blob.length + 4;
     429      762118 :         blob.data = talloc_array(sub_dir,
     430             :                                  uint8_t,
     431             :                                  blob.length);
     432      762118 :         if (blob.data == NULL) {
     433           0 :                 DBG_ERR("could not allocate for fuzz seeds! (%s)\n",
     434             :                         iface_name);
     435           0 :                 talloc_free(temp_ctx);
     436           0 :                 return;
     437             :         }
     438             : 
     439      762118 :         if (ndr64) {
     440           0 :                 fuzz_flags = 4;
     441             :         }
     442      762118 :         if (flags & NDR_IN) {
     443      381284 :                 fuzz_flags |= 1;
     444      380834 :         } else if (flags & NDR_OUT) {
     445      380834 :                 fuzz_flags |= 2;
     446             :         }
     447             : 
     448      762118 :         SSVAL(blob.data, 0, fuzz_flags);
     449      762118 :         SSVAL(blob.data, 2, opnum);
     450             : 
     451      762118 :         memcpy(&blob.data[4],
     452      762118 :                raw_blob.data,
     453             :                raw_blob.length);
     454             : 
     455             :         /*
     456             :          * This matches how oss-fuzz names the corpus input files, due
     457             :          * to a preference from libFuzzer
     458             :          */
     459      762118 :         rc = gnutls_hash_fast(GNUTLS_DIG_SHA1,
     460      762118 :                               blob.data,
     461             :                               blob.length,
     462             :                               digest);
     463      762118 :         if (rc < 0) {
     464             :                 /*
     465             :                  * This prints a better error message, eg if SHA1 is
     466             :                  * disabled
     467             :                  */
     468           0 :                 NTSTATUS status = gnutls_error_to_ntstatus(rc,
     469             :                                                   NT_STATUS_HASH_NOT_SUPPORTED);
     470           0 :                 DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s\n",
     471             :                         nt_errstr(status));
     472           0 :                 talloc_free(temp_ctx);
     473           0 :                 return;
     474             :         }
     475             : 
     476      762118 :         digest_blob.data = digest;
     477      762118 :         digest_blob.length = sizeof(digest);
     478      762118 :         digest_hex = data_blob_hex_string_lower(temp_ctx, &digest_blob);
     479             : 
     480      762118 :         fname = talloc_asprintf(temp_ctx, "%s/%s",
     481             :                                 sub_dir,
     482             :                                 digest_hex);
     483      762118 :         if (fname == NULL) {
     484           0 :                 talloc_free(temp_ctx);
     485           0 :                 return;
     486             :         }
     487             : 
     488             :         /*
     489             :          * If this fails, it is most likely because that file already
     490             :          * exists.  This is fine, it means we already have this
     491             :          * sample
     492             :          */
     493      762118 :         file_save(fname,
     494      762118 :                   blob.data,
     495             :                   blob.length);
     496             : 
     497      762118 :         talloc_free(temp_ctx);
     498             : }
     499             : 
     500             : #endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */

Generated by: LCOV version 1.14