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

Generated by: LCOV version 1.13