Ignore:
Timestamp:
Jun 9, 2016, 2:23:12 PM (9 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: apply latest security patches to trunk

Location:
trunk/server
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/server

  • trunk/server/librpc/rpc/dcerpc_util.c

    r862 r920  
    2828#include "librpc/gen_ndr/ndr_dcerpc.h"
    2929#include "rpc_common.h"
     30#include "lib/util/bitmap.h"
    3031
    3132/* we need to be able to get/set the fragment length without doing a full
     
    9293* @return               - A NTSTATUS error code.
    9394*/
    94 NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
     95NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
    9596                                  TALLOC_CTX *mem_ctx,
    96                                   DATA_BLOB *pkt_trailer,
     97                                  const DATA_BLOB *pkt_trailer,
    9798                                  struct dcerpc_auth *auth,
    98                                   uint32_t *auth_length,
     99                                  uint32_t *_auth_length,
    99100                                  bool auth_data_only)
    100101{
    101102        struct ndr_pull *ndr;
    102103        enum ndr_err_code ndr_err;
    103         uint32_t data_and_pad;
    104 
    105         data_and_pad = pkt_trailer->length
    106                         - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length);
    107 
    108         /* paranoia check for pad size. This would be caught anyway by
    109            the ndr_pull_advance() a few lines down, but it scared
    110            Jeremy enough for him to call me, so we might as well check
    111            it now, just to prevent someone posting a bogus YouTube
    112            video in the future.
    113         */
    114         if (data_and_pad > pkt_trailer->length) {
    115                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    116         }
    117 
    118         *auth_length = pkt_trailer->length - data_and_pad;
     104        uint16_t data_and_pad;
     105        uint16_t auth_length;
     106        uint32_t tmp_length;
     107
     108        ZERO_STRUCTP(auth);
     109        if (_auth_length != NULL) {
     110                *_auth_length = 0;
     111        }
     112
     113        /* Paranoia checks for auth_length. The caller should check this... */
     114        if (pkt->auth_length == 0) {
     115                return NT_STATUS_INTERNAL_ERROR;
     116        }
     117
     118        /* Paranoia checks for auth_length. The caller should check this... */
     119        if (pkt->auth_length > pkt->frag_length) {
     120                return NT_STATUS_INTERNAL_ERROR;
     121        }
     122        tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET;
     123        tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
     124        tmp_length += pkt->auth_length;
     125        if (tmp_length > pkt->frag_length) {
     126                return NT_STATUS_INTERNAL_ERROR;
     127        }
     128        if (pkt_trailer->length > UINT16_MAX) {
     129                return NT_STATUS_INTERNAL_ERROR;
     130        }
     131
     132        auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length;
     133        if (pkt_trailer->length < auth_length) {
     134                return NT_STATUS_RPC_PROTOCOL_ERROR;
     135        }
     136
     137        data_and_pad = pkt_trailer->length - auth_length;
    119138
    120139        ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx);
     
    136155        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    137156                talloc_free(ndr);
     157                ZERO_STRUCTP(auth);
    138158                return ndr_map_error2ntstatus(ndr_err);
    139159        }
    140160
    141         if (auth_data_only && data_and_pad != auth->auth_pad_length) {
    142                 DEBUG(1, (__location__ ": WARNING: pad length mismatch. "
     161        if (data_and_pad < auth->auth_pad_length) {
     162                DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
    143163                          "Calculated %u  got %u\n",
    144164                          (unsigned)data_and_pad,
    145165                          (unsigned)auth->auth_pad_length));
     166                talloc_free(ndr);
     167                ZERO_STRUCTP(auth);
     168                return NT_STATUS_RPC_PROTOCOL_ERROR;
     169        }
     170
     171        if (auth_data_only && data_and_pad != auth->auth_pad_length) {
     172                DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
     173                          "Calculated %u  got %u\n",
     174                          (unsigned)data_and_pad,
     175                          (unsigned)auth->auth_pad_length));
     176                talloc_free(ndr);
     177                ZERO_STRUCTP(auth);
     178                return NT_STATUS_RPC_PROTOCOL_ERROR;
    146179        }
    147180
     
    151184        talloc_steal(mem_ctx, auth->credentials.data);
    152185        talloc_free(ndr);
     186
     187        if (_auth_length != NULL) {
     188                *_auth_length = auth_length;
     189        }
     190
     191        return NT_STATUS_OK;
     192}
     193
     194/**
     195* @brief        Verify the fields in ncacn_packet header.
     196*
     197* @param pkt            - The ncacn_packet strcuture
     198* @param ptype          - The expected PDU type
     199* @param max_auth_info  - The maximum size of a possible auth trailer
     200* @param required_flags - The required flags for the pdu.
     201* @param optional_flags - The possible optional flags for the pdu.
     202*
     203* @return               - A NTSTATUS error code.
     204*/
     205NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
     206                                           enum dcerpc_pkt_type ptype,
     207                                           size_t max_auth_info,
     208                                           uint8_t required_flags,
     209                                           uint8_t optional_flags)
     210{
     211        if (pkt->rpc_vers != 5) {
     212                return NT_STATUS_RPC_PROTOCOL_ERROR;
     213        }
     214
     215        if (pkt->rpc_vers_minor != 0) {
     216                return NT_STATUS_RPC_PROTOCOL_ERROR;
     217        }
     218
     219        if (pkt->auth_length > pkt->frag_length) {
     220                return NT_STATUS_RPC_PROTOCOL_ERROR;
     221        }
     222
     223        if (pkt->ptype != ptype) {
     224                return NT_STATUS_RPC_PROTOCOL_ERROR;
     225        }
     226
     227        if (max_auth_info > UINT16_MAX) {
     228                return NT_STATUS_INTERNAL_ERROR;
     229        }
     230
     231        if (pkt->auth_length > 0) {
     232                size_t max_auth_length;
     233
     234                if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) {
     235                        return NT_STATUS_RPC_PROTOCOL_ERROR;
     236                }
     237                max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH;
     238
     239                if (pkt->auth_length > max_auth_length) {
     240                        return NT_STATUS_RPC_PROTOCOL_ERROR;
     241                }
     242        }
     243
     244        if ((pkt->pfc_flags & required_flags) != required_flags) {
     245                return NT_STATUS_RPC_PROTOCOL_ERROR;
     246        }
     247        if (pkt->pfc_flags & ~(optional_flags|required_flags)) {
     248                return NT_STATUS_RPC_PROTOCOL_ERROR;
     249        }
     250
     251        if (pkt->drep[0] & ~DCERPC_DREP_LE) {
     252                return NT_STATUS_RPC_PROTOCOL_ERROR;
     253        }
     254        if (pkt->drep[1] != 0) {
     255                return NT_STATUS_RPC_PROTOCOL_ERROR;
     256        }
     257        if (pkt->drep[2] != 0) {
     258                return NT_STATUS_RPC_PROTOCOL_ERROR;
     259        }
     260        if (pkt->drep[3] != 0) {
     261                return NT_STATUS_RPC_PROTOCOL_ERROR;
     262        }
    153263
    154264        return NT_STATUS_OK;
     
    342452        return NT_STATUS_OK;
    343453}
     454
     455struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struct ncacn_packet *pkt)
     456{
     457        struct dcerpc_sec_vt_header2 ret;
     458
     459        ZERO_STRUCT(ret);
     460        ret.ptype = pkt->ptype;
     461        memcpy(&ret.drep, pkt->drep, sizeof(ret.drep));
     462        ret.call_id = pkt->call_id;
     463
     464        switch (pkt->ptype) {
     465        case DCERPC_PKT_REQUEST:
     466                ret.context_id = pkt->u.request.context_id;
     467                ret.opnum      = pkt->u.request.opnum;
     468                break;
     469
     470        case DCERPC_PKT_RESPONSE:
     471                ret.context_id = pkt->u.response.context_id;
     472                break;
     473
     474        case DCERPC_PKT_FAULT:
     475                ret.context_id = pkt->u.fault.context_id;
     476                break;
     477
     478        default:
     479                break;
     480        }
     481
     482        return ret;
     483}
     484
     485bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
     486                                 const struct dcerpc_sec_vt_header2 *v2)
     487{
     488        if (v1->ptype != v2->ptype) {
     489                return false;
     490        }
     491
     492        if (memcmp(v1->drep, v2->drep, sizeof(v1->drep)) != 0) {
     493                return false;
     494        }
     495
     496        if (v1->call_id != v2->call_id) {
     497                return false;
     498        }
     499
     500        if (v1->context_id != v2->context_id) {
     501                return false;
     502        }
     503
     504        if (v1->opnum != v2->opnum) {
     505                return false;
     506        }
     507
     508        return true;
     509}
     510
     511static bool dcerpc_sec_vt_is_valid(const struct dcerpc_sec_verification_trailer *r)
     512{
     513        bool ret = false;
     514        TALLOC_CTX *frame = talloc_stackframe();
     515        struct bitmap *commands_seen;
     516        int i;
     517
     518        if (r->count.count == 0) {
     519                ret = true;
     520                goto done;
     521        }
     522
     523        if (memcmp(r->magic, DCERPC_SEC_VT_MAGIC, sizeof(r->magic)) != 0) {
     524                goto done;
     525        }
     526
     527        commands_seen = bitmap_talloc(frame, DCERPC_SEC_VT_COMMAND_ENUM + 1);
     528        if (commands_seen == NULL) {
     529                goto done;
     530        }
     531
     532        for (i=0; i < r->count.count; i++) {
     533                enum dcerpc_sec_vt_command_enum cmd =
     534                        r->commands[i].command & DCERPC_SEC_VT_COMMAND_ENUM;
     535
     536                if (bitmap_query(commands_seen, cmd)) {
     537                        /* Each command must appear at most once. */
     538                        goto done;
     539                }
     540                bitmap_set(commands_seen, cmd);
     541
     542                switch (cmd) {
     543                case DCERPC_SEC_VT_COMMAND_BITMASK1:
     544                case DCERPC_SEC_VT_COMMAND_PCONTEXT:
     545                case DCERPC_SEC_VT_COMMAND_HEADER2:
     546                        break;
     547                default:
     548                        if ((r->commands[i].u._unknown.length % 4) != 0) {
     549                                goto done;
     550                        }
     551                        break;
     552                }
     553        }
     554        ret = true;
     555done:
     556        TALLOC_FREE(frame);
     557        return ret;
     558}
     559
     560#define CHECK(msg, ok)                                          \
     561do {                                                            \
     562        if (!ok) {                                              \
     563                DEBUG(10, ("SEC_VT check %s failed\n", msg));   \
     564                return false;                                   \
     565        }                                                       \
     566} while(0)
     567
     568#define CHECK_SYNTAX(msg, s1, s2)                                       \
     569do {                                                            \
     570        if (!ndr_syntax_id_equal(&s1, &s2)) {                           \
     571                TALLOC_CTX *frame = talloc_stackframe();                \
     572                DEBUG(10, ("SEC_VT check %s failed: %s vs. %s\n", msg,  \
     573                           ndr_syntax_id_to_string(frame, &s1),         \
     574                           ndr_syntax_id_to_string(frame, &s1)));       \
     575                TALLOC_FREE(frame);                                     \
     576                return false;                                           \
     577        }                                                               \
     578} while(0)
     579
     580
     581bool dcerpc_sec_verification_trailer_check(
     582                const struct dcerpc_sec_verification_trailer *vt,
     583                const uint32_t *bitmask1,
     584                const struct dcerpc_sec_vt_pcontext *pcontext,
     585                const struct dcerpc_sec_vt_header2 *header2)
     586{
     587        size_t i;
     588
     589        if (!dcerpc_sec_vt_is_valid(vt)) {
     590                return false;
     591        }
     592
     593        for (i=0; i < vt->count.count; i++) {
     594                struct dcerpc_sec_vt *c = &vt->commands[i];
     595
     596                switch (c->command & DCERPC_SEC_VT_COMMAND_ENUM) {
     597                case DCERPC_SEC_VT_COMMAND_BITMASK1:
     598                        if (bitmask1 == NULL) {
     599                                CHECK("Bitmask1 must_process_command",
     600                                      !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
     601                                break;
     602                        }
     603
     604                        if (c->u.bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING) {
     605                                CHECK("Bitmask1 client_header_signing",
     606                                      *bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING);
     607                        }
     608                        break;
     609
     610                case DCERPC_SEC_VT_COMMAND_PCONTEXT:
     611                        if (pcontext == NULL) {
     612                                CHECK("Pcontext must_process_command",
     613                                      !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
     614                                break;
     615                        }
     616
     617                        CHECK_SYNTAX("Pcontect abstract_syntax",
     618                                     pcontext->abstract_syntax,
     619                                     c->u.pcontext.abstract_syntax);
     620                        CHECK_SYNTAX("Pcontext transfer_syntax",
     621                                     pcontext->transfer_syntax,
     622                                     c->u.pcontext.transfer_syntax);
     623                        break;
     624
     625                case DCERPC_SEC_VT_COMMAND_HEADER2: {
     626                        if (header2 == NULL) {
     627                                CHECK("Header2 must_process_command",
     628                                      !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
     629                                break;
     630                        }
     631
     632                        CHECK("Header2", dcerpc_sec_vt_header2_equal(header2, &c->u.header2));
     633                        break;
     634                }
     635
     636                default:
     637                        CHECK("Unknown must_process_command",
     638                              !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
     639                        break;
     640                }
     641        }
     642
     643        return true;
     644}
Note: See TracChangeset for help on using the changeset viewer.