LCOV - code coverage report
Current view: top level - librpc/rpc - dcerpc_pkt_auth.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 166 230 72.2 %
Date: 2024-01-11 09:59:51 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     1442639 : 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       13479 :         NTSTATUS status;
      53       13479 :         struct dcerpc_auth auth;
      54       13479 :         uint32_t auth_length;
      55             : 
      56     1442639 :         if (auth_state == NULL) {
      57           0 :                 return NT_STATUS_INTERNAL_ERROR;
      58             :         }
      59             : 
      60     1442639 :         status = dcerpc_verify_ncacn_packet_header(pkt, ptype,
      61             :                                         payload_and_verifier->length,
      62             :                                         required_flags, optional_flags);
      63     1442639 :         if (!NT_STATUS_IS_OK(status)) {
      64           0 :                 return status;
      65             :         }
      66             : 
      67     1442639 :         switch (auth_state->auth_level) {
      68      483939 :         case DCERPC_AUTH_LEVEL_PRIVACY:
      69             :         case DCERPC_AUTH_LEVEL_INTEGRITY:
      70             :         case DCERPC_AUTH_LEVEL_PACKET:
      71      483939 :                 break;
      72             : 
      73        3109 :         case DCERPC_AUTH_LEVEL_CONNECT:
      74        3109 :                 if (pkt->auth_length != 0) {
      75          49 :                         break;
      76             :                 }
      77      945200 :                 return NT_STATUS_OK;
      78      948807 :         case DCERPC_AUTH_LEVEL_NONE:
      79      948807 :                 if (pkt->auth_length != 0) {
      80           0 :                         return NT_STATUS_ACCESS_DENIED;
      81             :                 }
      82      948807 :                 return NT_STATUS_OK;
      83             : 
      84           0 :         default:
      85           0 :                 return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
      86             :         }
      87             : 
      88      490772 :         if (pkt->auth_length == 0) {
      89          12 :                 return NT_STATUS_RPC_PROTOCOL_ERROR;
      90             :         }
      91             : 
      92      490760 :         if (gensec == NULL) {
      93           0 :                 return NT_STATUS_INTERNAL_ERROR;
      94             :         }
      95             : 
      96      490760 :         status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
      97             :                                           payload_and_verifier,
      98             :                                           &auth, &auth_length, false);
      99      490760 :         if (!NT_STATUS_IS_OK(status)) {
     100           0 :                 return status;
     101             :         }
     102             : 
     103      490760 :         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      490760 :         payload_and_verifier->length -= auth_length;
     111             : 
     112      490760 :         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      490760 :         if (check_pkt_auth_fields) {
     120      481915 :                 if (auth.auth_type != auth_state->auth_type) {
     121           0 :                         return NT_STATUS_ACCESS_DENIED;
     122             :                 }
     123             : 
     124      481915 :                 if (auth.auth_level != auth_state->auth_level) {
     125           0 :                         return NT_STATUS_ACCESS_DENIED;
     126             :                 }
     127             : 
     128      481915 :                 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      490760 :         switch (auth_state->auth_level) {
     135      400460 :         case DCERPC_AUTH_LEVEL_PRIVACY:
     136      404592 :                 status = gensec_unseal_packet(gensec,
     137      396328 :                                               raw_packet->data + payload_offset,
     138             :                                               payload_and_verifier->length,
     139      400460 :                                               raw_packet->data,
     140      400460 :                                               raw_packet->length -
     141      400460 :                                               auth.credentials.length,
     142             :                                               &auth.credentials);
     143      400460 :                 if (!NT_STATUS_IS_OK(status)) {
     144           0 :                         return NT_STATUS_RPC_SEC_PKG_ERROR;
     145             :                 }
     146      407244 :                 memcpy(payload_and_verifier->data,
     147      400460 :                        raw_packet->data + payload_offset,
     148             :                        payload_and_verifier->length);
     149      396328 :                 break;
     150             : 
     151       90251 :         case DCERPC_AUTH_LEVEL_INTEGRITY:
     152             :         case DCERPC_AUTH_LEVEL_PACKET:
     153       92903 :                 status = gensec_check_packet(gensec,
     154       90251 :                                              payload_and_verifier->data,
     155             :                                              payload_and_verifier->length,
     156       90251 :                                              raw_packet->data,
     157       90251 :                                              raw_packet->length -
     158       90251 :                                              auth.credentials.length,
     159             :                                              &auth.credentials);
     160       90251 :                 if (!NT_STATUS_IS_OK(status)) {
     161          21 :                         return NT_STATUS_RPC_SEC_PKG_ERROR;
     162             :                 }
     163       87578 :                 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      490739 :         payload_and_verifier->length -= auth.auth_pad_length;
     179             : 
     180      490739 :         return NT_STATUS_OK;
     181             : }
     182             : 
     183     1440012 : 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     1440012 :         TALLOC_CTX *frame = talloc_stackframe();
     193       13482 :         NTSTATUS status;
     194       13482 :         enum ndr_err_code ndr_err;
     195     1440012 :         struct ndr_push *ndr = NULL;
     196       13482 :         uint32_t payload_length;
     197       13482 :         uint32_t whole_length;
     198     1440012 :         DATA_BLOB blob = data_blob_null;
     199     1440012 :         DATA_BLOB sig = data_blob_null;
     200       13482 :         struct dcerpc_auth _out_auth_info;
     201     1440012 :         struct dcerpc_auth *out_auth_info = NULL;
     202             : 
     203     1440012 :         *raw_packet = data_blob_null;
     204             : 
     205     1440012 :         if (auth_state == NULL) {
     206           0 :                 TALLOC_FREE(frame);
     207           0 :                 return NT_STATUS_INTERNAL_ERROR;
     208             :         }
     209             : 
     210     1440012 :         switch (auth_state->auth_level) {
     211      490648 :         case DCERPC_AUTH_LEVEL_PRIVACY:
     212             :         case DCERPC_AUTH_LEVEL_INTEGRITY:
     213             :         case DCERPC_AUTH_LEVEL_PACKET:
     214      490648 :                 if (sig_size == 0) {
     215           0 :                         TALLOC_FREE(frame);
     216           0 :                         return NT_STATUS_INTERNAL_ERROR;
     217             :                 }
     218             : 
     219      490648 :                 if (gensec == NULL) {
     220           0 :                         TALLOC_FREE(frame);
     221           0 :                         return NT_STATUS_INTERNAL_ERROR;
     222             :                 }
     223             : 
     224      490648 :                 _out_auth_info = (struct dcerpc_auth) {
     225      490648 :                         .auth_type = auth_state->auth_type,
     226      483863 :                         .auth_level = auth_state->auth_level,
     227      490648 :                         .auth_context_id = auth_state->auth_context_id,
     228             :                 };
     229      490648 :                 out_auth_info = &_out_auth_info;
     230      490648 :                 break;
     231             : 
     232        3079 :         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        3079 :                 if (sig_size != 0) {
     238           0 :                         TALLOC_FREE(frame);
     239           0 :                         return NT_STATUS_INTERNAL_ERROR;
     240             :                 }
     241             : 
     242        3079 :                 if (gensec == NULL) {
     243           0 :                         TALLOC_FREE(frame);
     244           0 :                         return NT_STATUS_INTERNAL_ERROR;
     245             :                 }
     246        3051 :                 break;
     247             : 
     248      946285 :         case DCERPC_AUTH_LEVEL_NONE:
     249      946285 :                 if (sig_size != 0) {
     250           0 :                         TALLOC_FREE(frame);
     251           0 :                         return NT_STATUS_INTERNAL_ERROR;
     252             :                 }
     253      939616 :                 break;
     254             : 
     255           0 :         default:
     256           0 :                 TALLOC_FREE(frame);
     257           0 :                 return NT_STATUS_INTERNAL_ERROR;
     258             :         }
     259             : 
     260     1440012 :         ndr = ndr_push_init_ctx(frame);
     261     1440012 :         if (ndr == NULL) {
     262           0 :                 TALLOC_FREE(frame);
     263           0 :                 return NT_STATUS_NO_MEMORY;
     264             :         }
     265             : 
     266     1440012 :         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
     267     1440012 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     268           0 :                 TALLOC_FREE(frame);
     269           0 :                 return ndr_map_error2ntstatus(ndr_err);
     270             :         }
     271             : 
     272     1440012 :         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      349758 :                 out_auth_info->auth_pad_length =
     281      490648 :                         DCERPC_AUTH_PAD_LENGTH(payload->length);
     282      490648 :                 ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length);
     283      490648 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     284           0 :                         TALLOC_FREE(frame);
     285           0 :                         return ndr_map_error2ntstatus(ndr_err);
     286             :                 }
     287             : 
     288      490648 :                 payload_length = payload->length +
     289      490648 :                         out_auth_info->auth_pad_length;
     290             : 
     291      490648 :                 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
     292             :                                                out_auth_info);
     293      490648 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     294           0 :                         TALLOC_FREE(frame);
     295           0 :                         return ndr_map_error2ntstatus(ndr_err);
     296             :                 }
     297             : 
     298      490648 :                 whole_length = ndr->offset;
     299             : 
     300      490648 :                 ndr_err = ndr_push_zero(ndr, sig_size);
     301      490648 :                 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      949364 :                 payload_length = payload->length;
     307      949364 :                 whole_length = ndr->offset;
     308             :         }
     309             : 
     310             :         /* extract the whole packet as a blob */
     311     1440012 :         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     1440012 :         dcerpc_set_frag_length(&blob, blob.length);
     320     1440012 :         dcerpc_set_auth_length(&blob, sig_size);
     321             : 
     322             :         /* sign or seal the packet */
     323     1440012 :         switch (auth_state->auth_level) {
     324      400515 :         case DCERPC_AUTH_LEVEL_PRIVACY:
     325      404648 :                 status = gensec_seal_packet(gensec,
     326             :                                             frame,
     327      396382 :                                             blob.data + payload_offset,
     328             :                                             payload_length,
     329      400515 :                                             blob.data,
     330             :                                             whole_length,
     331             :                                             &sig);
     332      400515 :                 if (!NT_STATUS_IS_OK(status)) {
     333           0 :                         TALLOC_FREE(frame);
     334           0 :                         return status;
     335             :                 }
     336      396382 :                 break;
     337             : 
     338       90133 :         case DCERPC_AUTH_LEVEL_INTEGRITY:
     339             :         case DCERPC_AUTH_LEVEL_PACKET:
     340       92785 :                 status = gensec_sign_packet(gensec,
     341             :                                             frame,
     342       90133 :                                             blob.data + payload_offset,
     343             :                                             payload_length,
     344       90133 :                                             blob.data,
     345             :                                             whole_length,
     346             :                                             &sig);
     347       90133 :                 if (!NT_STATUS_IS_OK(status)) {
     348           0 :                         TALLOC_FREE(frame);
     349           0 :                         return status;
     350             :                 }
     351       87481 :                 break;
     352             : 
     353      942667 :         case DCERPC_AUTH_LEVEL_CONNECT:
     354             :         case DCERPC_AUTH_LEVEL_NONE:
     355      942667 :                 break;
     356             : 
     357           0 :         default:
     358           0 :                 TALLOC_FREE(frame);
     359           0 :                 return NT_STATUS_INTERNAL_ERROR;
     360             :         }
     361             : 
     362     1440012 :         if (sig.length != sig_size) {
     363           0 :                 TALLOC_FREE(frame);
     364           0 :                 return NT_STATUS_RPC_SEC_PKG_ERROR;
     365             :         }
     366             : 
     367     1440012 :         if (sig_size != 0) {
     368      490648 :                 memcpy(blob.data + whole_length, sig.data, sig_size);
     369             :         }
     370             : 
     371     1440012 :         *raw_packet = blob;
     372     1440012 :         talloc_steal(mem_ctx, raw_packet->data);
     373     1440012 :         TALLOC_FREE(frame);
     374     1440012 :         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     1680389 : 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     1680389 :         char *fname = NULL;
     392     1680389 :         const char *sub_dir = NULL;
     393     1680389 :         TALLOC_CTX *temp_ctx = talloc_new(mem_ctx);
     394       13344 :         DATA_BLOB blob;
     395       13344 :         int ret, rc;
     396       13344 :         uint8_t digest[20];
     397       13344 :         DATA_BLOB digest_blob;
     398       13344 :         char *digest_hex;
     399     1680389 :         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     1680389 :         if (dump_dir == NULL) {
     409      936420 :                 return;
     410             :         }
     411             : 
     412      743969 :         temp_ctx = talloc_stackframe();
     413             : 
     414      743969 :         sub_dir = talloc_asprintf(temp_ctx, "%s/%s",
     415             :                                   dump_dir,
     416             :                                   iface_name);
     417      743969 :         if (sub_dir == NULL) {
     418           0 :                 talloc_free(temp_ctx);
     419           0 :                 return;
     420             :         }
     421      743969 :         ret = mkdir_p(sub_dir, 0755);
     422      743969 :         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      743969 :         blob.length = raw_blob.length + 4;
     429      743969 :         blob.data = talloc_array(sub_dir,
     430             :                                  uint8_t,
     431             :                                  blob.length);
     432      743969 :         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      743969 :         if (ndr64) {
     440           0 :                 fuzz_flags = 4;
     441             :         }
     442      743969 :         if (flags & NDR_IN) {
     443      372193 :                 fuzz_flags |= 1;
     444      371776 :         } else if (flags & NDR_OUT) {
     445      371776 :                 fuzz_flags |= 2;
     446             :         }
     447             : 
     448      743969 :         SSVAL(blob.data, 0, fuzz_flags);
     449      743969 :         SSVAL(blob.data, 2, opnum);
     450             : 
     451      743969 :         memcpy(&blob.data[4],
     452      743969 :                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      743969 :         rc = gnutls_hash_fast(GNUTLS_DIG_SHA1,
     460      743969 :                               blob.data,
     461             :                               blob.length,
     462             :                               digest);
     463      743969 :         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      743969 :         digest_blob.data = digest;
     477      743969 :         digest_blob.length = sizeof(digest);
     478      743969 :         digest_hex = data_blob_hex_string_lower(temp_ctx, &digest_blob);
     479             : 
     480      743969 :         fname = talloc_asprintf(temp_ctx, "%s/%s",
     481             :                                 sub_dir,
     482             :                                 digest_hex);
     483      743969 :         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      743969 :         file_save(fname,
     494      743969 :                   blob.data,
     495             :                   blob.length);
     496             : 
     497      743969 :         talloc_free(temp_ctx);
     498             : }
     499             : 
     500             : #endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */

Generated by: LCOV version 1.14