media/mtransport/third_party/nICEr/src/stun/stun_proc.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /*
     2 Copyright (c) 2007, Adobe Systems, Incorporated
     3 All rights reserved.
     5 Redistribution and use in source and binary forms, with or without
     6 modification, are permitted provided that the following conditions are
     7 met:
     9 * Redistributions of source code must retain the above copyright
    10   notice, this list of conditions and the following disclaimer.
    12 * Redistributions in binary form must reproduce the above copyright
    13   notice, this list of conditions and the following disclaimer in the
    14   documentation and/or other materials provided with the distribution.
    16 * Neither the name of Adobe Systems, Network Resonance nor the names of its
    17   contributors may be used to endorse or promote products derived from
    18   this software without specific prior written permission.
    20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31 */
    34 static char *RCSSTRING __UNUSED__="$Id: stun_proc.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
    36 #include <errno.h>
    37 #include <csi_platform.h>
    39 #ifdef WIN32
    40 #include <winsock2.h>
    41 #include <stdlib.h>
    42 #include <io.h>
    43 #include <time.h>
    44 #else   /* UNIX */
    45 #include <string.h>
    46 #endif  /* end UNIX */
    47 #include <assert.h>
    49 #include "stun.h"
    50 #include "stun_reg.h"
    51 #include "registry.h"
    53 static int
    54 nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res);
    56 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3 */
    57 int
    58 nr_stun_receive_message(nr_stun_message *req, nr_stun_message *msg)
    59 {
    60     int _status;
    61     nr_stun_message_attribute *attr;
    63 #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
    64     /* if this message was generated by an RFC 3489 impementation,
    65      * the call to nr_is_stun_message will fail, so skip that
    66      * check and puke elsewhere if the message can't be decoded */
    67     if (msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE
    68      || msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE2) {
    69 #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
    70     if (!nr_is_stun_message(msg->buffer, msg->length)) {
    71         r_log(NR_LOG_STUN, LOG_WARNING, "Not a STUN message");
    72         ABORT(R_REJECTED);
    73     }
    74 #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
    75     }
    76 #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
    78     if (req == 0) {
    79         if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_REQUEST) {
    80             r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message type: %03x", msg->header.type);
    81             ABORT(R_REJECTED);
    82         }
    83     }
    84     else {
    85         if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_RESPONSE
    86          && NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_ERROR_RESPONSE) {
    87             r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message class: %03x", msg->header.type);
    88             ABORT(R_REJECTED);
    89         }
    91         if (NR_STUN_GET_TYPE_METHOD(req->header.type) != NR_STUN_GET_TYPE_METHOD(msg->header.type)) {
    92             r_log(NR_LOG_STUN,LOG_WARNING,"Inconsistent message method: %03x expected %03x", msg->header.type, req->header.type);
    93             ABORT(R_REJECTED);
    94         }
    96         if (nr_stun_different_transaction(msg->buffer, msg->length, req)) {
    97             r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized STUN transaction");
    98             ABORT(R_REJECTED);
    99         }
   100     }
   102     switch (msg->header.magic_cookie) {
   103     case NR_STUN_MAGIC_COOKIE:
   104         /* basically draft-ietf-behave-rfc3489bis-10.txt S 6 rules */
   106         if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT, &attr)
   107          && !attr->u.fingerprint.valid) {
   108             r_log(NR_LOG_STUN, LOG_WARNING, "Invalid fingerprint");
   109             ABORT(R_REJECTED);
   110         }
   112         break;
   114 #ifdef USE_STUND_0_96
   115     case NR_STUN_MAGIC_COOKIE2:
   116         /* nothing to check in this case */
   117         break;
   118 #endif /* USE_STUND_0_96 */
   120     default:
   121 #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
   122         /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   123 #else
   124 #ifdef NDEBUG
   125         /* in deployment builds we should always see a recognized magic cookie */
   126         r_log(NR_LOG_STUN, LOG_WARNING, "Missing Magic Cookie");
   127         ABORT(R_REJECTED);
   128 #else
   129         /* ignore this condition because sometimes we like to pretend we're
   130          * a server talking to old clients and their messages don't contain
   131          * a magic cookie at all but rather the magic cookie field is part
   132          * of their ID and therefore random */
   133 #endif /* NDEBUG */
   134 #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
   135         break;
   136     }
   138     _status=0;
   139   abort:
   140     return _status;
   141 }
   143 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1 */
   144 int
   145 nr_stun_process_request(nr_stun_message *req, nr_stun_message *res)
   146 {
   147     int _status;
   148 #ifdef USE_STUN_PEDANTIC
   149     int r;
   150     nr_stun_attr_unknown_attributes unknown_attributes = { { 0 } };
   151     nr_stun_message_attribute *attr;
   153     if (req->comprehension_required_unknown_attributes > 0) {
   154         nr_stun_form_error_response(req, res, 420, "Unknown Attributes");
   156         TAILQ_FOREACH(attr, &req->attributes, entry) {
   157             if (attr->name == 0) {
   158                 /* unrecognized attribute */
   160                 /* should never happen, but truncate if it ever were to occur */
   161                 if (unknown_attributes.num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES)
   162                     break;
   164                 unknown_attributes.attribute[unknown_attributes.num_attributes++] = attr->type;
   165             }
   166         }
   168         assert(req->comprehension_required_unknown_attributes + req->comprehension_optional_unknown_attributes == unknown_attributes.num_attributes);
   170         if ((r=nr_stun_message_add_unknown_attributes_attribute(res, &unknown_attributes)))
   171             ABORT(R_ALREADY);
   173         ABORT(R_ALREADY);
   174     }
   175 #endif /* USE_STUN_PEDANTIC */
   177     _status=0;
   178 #ifdef USE_STUN_PEDANTIC
   179   abort:
   180 #endif /* USE_STUN_PEDANTIC */
   181     return _status;
   182 }
   184 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.2 */
   185 int
   186 nr_stun_process_indication(nr_stun_message *ind)
   187 {
   188     int _status;
   189 #ifdef USE_STUN_PEDANTIC
   191     if (ind->comprehension_required_unknown_attributes > 0)
   192         ABORT(R_REJECTED);
   193 #endif /* USE_STUN_PEDANTIC */
   195     _status=0;
   196 #ifdef USE_STUN_PEDANTIC
   197   abort:
   198 #endif /* USE_STUN_PEDANTIC */
   199     return _status;
   200 }
   202 /* RFC5389 S 7.3.3, except that we *also* allow a MAPPED_ADDRESS
   203    to compensate for a bug in Google's STUN server where it
   204    always returns MAPPED_ADDRESS.
   206    Mozilla bug: 888274.
   207  */
   208 int
   209 nr_stun_process_success_response(nr_stun_message *res)
   210 {
   211     int _status;
   213 #ifdef USE_STUN_PEDANTIC
   214     if (res->comprehension_required_unknown_attributes > 0)
   215         ABORT(R_REJECTED);
   216 #endif /* USE_STUN_PEDANTIC */
   218     if (NR_STUN_GET_TYPE_METHOD(res->header.type) == NR_METHOD_BINDING) {
   219         if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0) &&
   220             ! nr_stun_message_has_attribute(res, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) {
   221             r_log(NR_LOG_STUN, LOG_WARNING, "Missing XOR-MAPPED-ADDRESS and MAPPED_ADDRESS");
   222             ABORT(R_REJECTED);
   223         }
   224     }
   226     _status=0;
   227  abort:
   228     return _status;
   229 }
   231 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.4 */
   232 int
   233 nr_stun_process_error_response(nr_stun_message *res, UINT2 *error_code)
   234 {
   235     int _status;
   236     nr_stun_message_attribute *attr;
   238     if (res->comprehension_required_unknown_attributes > 0) {
   239         ABORT(R_REJECTED);
   240     }
   242     if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_ERROR_CODE, &attr)) {
   243         r_log(NR_LOG_STUN, LOG_WARNING, "Missing ERROR-CODE");
   244         ABORT(R_REJECTED);
   245     }
   247     *error_code = attr->u.error_code.number;
   249     switch (attr->u.error_code.number / 100) {
   250     case 3:
   251         /* If the error code is 300 through 399, the client SHOULD consider
   252          * the transaction as failed unless the ALTERNATE-SERVER extension is
   253          * being used.  See Section 11. */
   255         if (attr->u.error_code.number == 300) {
   256             if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_ALTERNATE_SERVER, 0)) {
   257                 r_log(NR_LOG_STUN, LOG_WARNING, "Missing ALTERNATE-SERVER");
   258                 ABORT(R_REJECTED);
   259             }
   261             /* draft-ietf-behave-rfc3489bis-10.txt S 11 */
   262             if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
   263                 r_log(NR_LOG_STUN, LOG_WARNING, "Missing MESSAGE-INTEGRITY");
   264                 ABORT(R_REJECTED);
   265             }
   267             ABORT(R_RETRY);
   268         }
   270         ABORT(R_REJECTED);
   271         break;
   273     case 4:
   274         /* If the error code is 400 through 499, the client declares the
   275          * transaction failed; in the case of 420 (Unknown Attribute), the
   276          * response should contain a UNKNOWN-ATTRIBUTES attribute that gives
   277          * additional information. */
   278         if (attr->u.error_code.number == 420)
   279             ABORT(R_REJECTED);
   281         /* it may be possible to restart given the info that was received in
   282          * this response, so retry */
   283         ABORT(R_RETRY);
   284         break;
   286     case 5:
   287         /* If the error code is 500 through 599, the client MAY resend the
   288          * request; clients that do so MUST limit the number of times they do
   289          * this. */
   290         /* let the retransmit mechanism handle resending the request */
   291         break;
   293     default:
   294         ABORT(R_REJECTED);
   295         break;
   296     }
   298     /* the spec says: "The client then does any processing specified by the authentication
   299      * mechanism (see Section 10).  This may result in a new transaction
   300      * attempt." -- but this is handled already elsewhere, so needn't be repeated
   301      * in this function */
   303     _status=0;
   304  abort:
   305     return _status;
   306 }
   308 /* draft-ietf-behave-rfc3489bis-10.txt S 10.1.2 */
   309 int
   310 nr_stun_receive_request_or_indication_short_term_auth(nr_stun_message *msg,
   311                                                       nr_stun_message *res)
   312 {
   313     int _status;
   314     nr_stun_message_attribute *attr;
   316     switch (msg->header.magic_cookie) {
   317     default:
   318         /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   319         /* drop thru */
   320     case NR_STUN_MAGIC_COOKIE:
   321         if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
   322             nr_stun_form_error_response(msg, res, 400, "Missing MESSAGE-INTEGRITY");
   323             ABORT(R_ALREADY);
   324         }
   326         if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_USERNAME, 0)) {
   327             nr_stun_form_error_response(msg, res, 400, "Missing USERNAME");
   328             ABORT(R_ALREADY);
   329         }
   331         if (attr->u.message_integrity.unknown_user) {
   332             nr_stun_form_error_response(msg, res, 401, "Unrecognized USERNAME");
   333             ABORT(R_ALREADY);
   334         }
   336         if (!attr->u.message_integrity.valid) {
   337             nr_stun_form_error_response(msg, res, 401, "Bad MESSAGE-INTEGRITY");
   338             ABORT(R_ALREADY);
   339         }
   341         break;
   343 #ifdef USE_STUND_0_96
   344     case NR_STUN_MAGIC_COOKIE2:
   345         /* nothing to check in this case */
   346         break;
   347 #endif /* USE_STUND_0_96 */
   348     }
   350     _status=0;
   351  abort:
   352     return _status;
   353 }
   355 /* draft-ietf-behave-rfc3489bis-10.txt S 10.1.3 */
   356 int
   357 nr_stun_receive_response_short_term_auth(nr_stun_message *res)
   358 {
   359     int _status;
   360     nr_stun_message_attribute *attr;
   362     switch (res->header.magic_cookie) {
   363     default:
   364         /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   365         /* drop thru */
   366     case NR_STUN_MAGIC_COOKIE:
   367         if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
   368             r_log(NR_LOG_STUN, LOG_WARNING, "Missing MESSAGE-INTEGRITY");
   369             ABORT(R_REJECTED);
   370         }
   372         if (!attr->u.message_integrity.valid) {
   373             r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY");
   374             ABORT(R_REJECTED);
   375         }
   377         break;
   379 #ifdef USE_STUND_0_96
   380     case NR_STUN_MAGIC_COOKIE2:
   381         /* nothing to check in this case */
   382         break;
   383 #endif /* USE_STUND_0_96 */
   384     }
   386    _status=0;
   387  abort:
   388      return _status;
   389 }
   391 static int
   392 nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res)
   393 {
   394     int r,_status;
   395     char *realm = 0;
   396     char *nonce;
   397     UINT2 size;
   399     if ((r=NR_reg_alloc_string(NR_STUN_REG_PREF_SERVER_REALM, &realm)))
   400         ABORT(r);
   402     if ((r=nr_stun_message_add_realm_attribute(res, realm)))
   403         ABORT(r);
   405     if (clnt) {
   406         if (strlen(clnt->nonce) < 1)
   407             new_nonce = 1;
   409         if (new_nonce) {
   410             if (NR_reg_get_uint2(NR_STUN_REG_PREF_SERVER_NONCE_SIZE, &size))
   411                 size = 48;
   413             if (size > (sizeof(clnt->nonce) - 1))
   414                 size = sizeof(clnt->nonce) - 1;
   416             nr_random_alphanum(clnt->nonce, size);
   417             clnt->nonce[size] = '\0';
   418         }
   420         nonce = clnt->nonce;
   421     }
   422     else {
   423         /* user is not known, so use a bogus nonce since there's no way to
   424          * store a good nonce with the client-specific data -- this nonce
   425          * will be recognized as stale if the client attempts another
   426          * request */
   427         nonce = "STALE";
   428     }
   430     if ((r=nr_stun_message_add_nonce_attribute(res, nonce)))
   431         ABORT(r);
   433     _status=0;
   434  abort:
   435 #ifdef USE_TURN
   436 assert(_status == 0); /* TODO: !nn! cleanup after I reimplmement TURN */
   437 #endif
   438     RFREE(realm);
   439     return _status;
   440 }
   442 /* draft-ietf-behave-rfc3489bis-10.txt S 10.2.1 - 10.2.2 */
   443 int
   444 nr_stun_receive_request_long_term_auth(nr_stun_message *req, nr_stun_server_ctx *ctx, nr_stun_message *res)
   445 {
   446     int r,_status;
   447     nr_stun_message_attribute *mi;
   448     nr_stun_message_attribute *n;
   449     nr_stun_server_client *clnt = 0;
   451     switch (req->header.magic_cookie) {
   452     default:
   453         /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   454         /* drop thru */
   455     case NR_STUN_MAGIC_COOKIE:
   456         if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, 0)) {
   457             nr_stun_form_error_response(req, res, 400, "Missing USERNAME");
   458             nr_stun_add_realm_and_nonce(0, 0, res);
   459             ABORT(R_ALREADY);
   460         }
   462         if ((r=nr_stun_get_message_client(ctx, req, &clnt))) {
   463             nr_stun_form_error_response(req, res, 401, "Unrecognized USERNAME");
   464             nr_stun_add_realm_and_nonce(0, 0, res);
   465             ABORT(R_ALREADY);
   466         }
   468         if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, &mi)) {
   469             nr_stun_form_error_response(req, res, 401, "Missing MESSAGE-INTEGRITY");
   470             nr_stun_add_realm_and_nonce(0, clnt, res);
   471             ABORT(R_ALREADY);
   472         }
   474         assert(!mi->u.message_integrity.unknown_user);
   476         if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_REALM, 0)) {
   477             nr_stun_form_error_response(req, res, 400, "Missing REALM");
   478             ABORT(R_ALREADY);
   479         }
   481         if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_NONCE, &n)) {
   482             nr_stun_form_error_response(req, res, 400, "Missing NONCE");
   483             ABORT(R_ALREADY);
   484         }
   486         assert(sizeof(clnt->nonce) == sizeof(n->u.nonce));
   487         if (strncmp(clnt->nonce, n->u.nonce, sizeof(n->u.nonce))) {
   488             nr_stun_form_error_response(req, res, 438, "Stale NONCE");
   489             nr_stun_add_realm_and_nonce(1, clnt, res);
   490             ABORT(R_ALREADY);
   491         }
   493         if (!mi->u.message_integrity.valid) {
   494             nr_stun_form_error_response(req, res, 401, "Bad MESSAGE-INTEGRITY");
   495             nr_stun_add_realm_and_nonce(0, clnt, res);
   496             ABORT(R_ALREADY);
   497         }
   499         break;
   501 #ifdef USE_STUND_0_96
   502     case NR_STUN_MAGIC_COOKIE2:
   503         /* nothing to do in this case */
   504         break;
   505 #endif /* USE_STUND_0_96 */
   506     }
   508     _status=0;
   509  abort:
   511     return _status;
   512 }
   514 /* draft-ietf-behave-rfc3489bis-10.txt S 10.2.3 */
   515 int
   516 nr_stun_receive_response_long_term_auth(nr_stun_message *res, nr_stun_client_ctx *ctx)
   517 {
   518     int _status;
   519     nr_stun_message_attribute *attr;
   521     switch (res->header.magic_cookie) {
   522     default:
   523         /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   524         /* drop thru */
   525     case NR_STUN_MAGIC_COOKIE:
   526         if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_REALM, &attr)) {
   527             RFREE(ctx->realm);
   528             ctx->realm = r_strdup(attr->u.realm);
   529             if (!ctx->realm)
   530                 ABORT(R_NO_MEMORY);
   531         }
   532         else {
   533             r_log(NR_LOG_STUN, LOG_WARNING, "Missing REALM");
   534             ABORT(R_REJECTED);
   535         }
   537         if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_NONCE, &attr)) {
   538             RFREE(ctx->nonce);
   539             ctx->nonce = r_strdup(attr->u.nonce);
   540             if (!ctx->nonce)
   541                 ABORT(R_NO_MEMORY);
   542         }
   543         else {
   544             r_log(NR_LOG_STUN, LOG_WARNING, "Missing NONCE");
   545             ABORT(R_REJECTED);
   546         }
   548         if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
   549             if (!attr->u.message_integrity.valid) {
   550                 r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY");
   551                 ABORT(R_REJECTED);
   552             }
   553         }
   555         break;
   557 #ifdef USE_STUND_0_96
   558     case NR_STUN_MAGIC_COOKIE2:
   559         /* nothing to check in this case */
   560         break;
   561 #endif /* USE_STUND_0_96 */
   562     }
   564     _status=0;
   565  abort:
   566     return _status;
   567 }

mercurial