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

Generated by: LCOV version 1.14