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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/mtransport/third_party/nICEr/src/stun/stun_proc.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,568 @@
     1.4 +/*
     1.5 +Copyright (c) 2007, Adobe Systems, Incorporated
     1.6 +All rights reserved.
     1.7 +
     1.8 +Redistribution and use in source and binary forms, with or without
     1.9 +modification, are permitted provided that the following conditions are
    1.10 +met:
    1.11 +
    1.12 +* Redistributions of source code must retain the above copyright
    1.13 +  notice, this list of conditions and the following disclaimer.
    1.14 +
    1.15 +* Redistributions in binary form must reproduce the above copyright
    1.16 +  notice, this list of conditions and the following disclaimer in the
    1.17 +  documentation and/or other materials provided with the distribution.
    1.18 +
    1.19 +* Neither the name of Adobe Systems, Network Resonance nor the names of its
    1.20 +  contributors may be used to endorse or promote products derived from
    1.21 +  this software without specific prior written permission.
    1.22 +
    1.23 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.24 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.25 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.26 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    1.27 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.28 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.29 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.30 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.31 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.32 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.33 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.34 +*/
    1.35 +
    1.36 +
    1.37 +static char *RCSSTRING __UNUSED__="$Id: stun_proc.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
    1.38 +
    1.39 +#include <errno.h>
    1.40 +#include <csi_platform.h>
    1.41 +
    1.42 +#ifdef WIN32
    1.43 +#include <winsock2.h>
    1.44 +#include <stdlib.h>
    1.45 +#include <io.h>
    1.46 +#include <time.h>
    1.47 +#else   /* UNIX */
    1.48 +#include <string.h>
    1.49 +#endif  /* end UNIX */
    1.50 +#include <assert.h>
    1.51 +
    1.52 +#include "stun.h"
    1.53 +#include "stun_reg.h"
    1.54 +#include "registry.h"
    1.55 +
    1.56 +static int
    1.57 +nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res);
    1.58 +
    1.59 +/* draft-ietf-behave-rfc3489bis-10.txt S 7.3 */
    1.60 +int
    1.61 +nr_stun_receive_message(nr_stun_message *req, nr_stun_message *msg)
    1.62 +{
    1.63 +    int _status;
    1.64 +    nr_stun_message_attribute *attr;
    1.65 +
    1.66 +#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
    1.67 +    /* if this message was generated by an RFC 3489 impementation,
    1.68 +     * the call to nr_is_stun_message will fail, so skip that
    1.69 +     * check and puke elsewhere if the message can't be decoded */
    1.70 +    if (msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE
    1.71 +     || msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE2) {
    1.72 +#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
    1.73 +    if (!nr_is_stun_message(msg->buffer, msg->length)) {
    1.74 +        r_log(NR_LOG_STUN, LOG_WARNING, "Not a STUN message");
    1.75 +        ABORT(R_REJECTED);
    1.76 +    }
    1.77 +#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
    1.78 +    }
    1.79 +#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
    1.80 +
    1.81 +    if (req == 0) {
    1.82 +        if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_REQUEST) {
    1.83 +            r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message type: %03x", msg->header.type);
    1.84 +            ABORT(R_REJECTED);
    1.85 +        }
    1.86 +    }
    1.87 +    else {
    1.88 +        if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_RESPONSE
    1.89 +         && NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_ERROR_RESPONSE) {
    1.90 +            r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message class: %03x", msg->header.type);
    1.91 +            ABORT(R_REJECTED);
    1.92 +        }
    1.93 +
    1.94 +        if (NR_STUN_GET_TYPE_METHOD(req->header.type) != NR_STUN_GET_TYPE_METHOD(msg->header.type)) {
    1.95 +            r_log(NR_LOG_STUN,LOG_WARNING,"Inconsistent message method: %03x expected %03x", msg->header.type, req->header.type);
    1.96 +            ABORT(R_REJECTED);
    1.97 +        }
    1.98 +
    1.99 +        if (nr_stun_different_transaction(msg->buffer, msg->length, req)) {
   1.100 +            r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized STUN transaction");
   1.101 +            ABORT(R_REJECTED);
   1.102 +        }
   1.103 +    }
   1.104 +
   1.105 +    switch (msg->header.magic_cookie) {
   1.106 +    case NR_STUN_MAGIC_COOKIE:
   1.107 +        /* basically draft-ietf-behave-rfc3489bis-10.txt S 6 rules */
   1.108 +
   1.109 +        if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT, &attr)
   1.110 +         && !attr->u.fingerprint.valid) {
   1.111 +            r_log(NR_LOG_STUN, LOG_WARNING, "Invalid fingerprint");
   1.112 +            ABORT(R_REJECTED);
   1.113 +        }
   1.114 +
   1.115 +        break;
   1.116 +
   1.117 +#ifdef USE_STUND_0_96
   1.118 +    case NR_STUN_MAGIC_COOKIE2:
   1.119 +        /* nothing to check in this case */
   1.120 +        break;
   1.121 +#endif /* USE_STUND_0_96 */
   1.122 +
   1.123 +    default:
   1.124 +#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
   1.125 +        /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   1.126 +#else
   1.127 +#ifdef NDEBUG
   1.128 +        /* in deployment builds we should always see a recognized magic cookie */
   1.129 +        r_log(NR_LOG_STUN, LOG_WARNING, "Missing Magic Cookie");
   1.130 +        ABORT(R_REJECTED);
   1.131 +#else
   1.132 +        /* ignore this condition because sometimes we like to pretend we're
   1.133 +         * a server talking to old clients and their messages don't contain
   1.134 +         * a magic cookie at all but rather the magic cookie field is part
   1.135 +         * of their ID and therefore random */
   1.136 +#endif /* NDEBUG */
   1.137 +#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
   1.138 +        break;
   1.139 +    }
   1.140 +
   1.141 +    _status=0;
   1.142 +  abort:
   1.143 +    return _status;
   1.144 +}
   1.145 +
   1.146 +/* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1 */
   1.147 +int
   1.148 +nr_stun_process_request(nr_stun_message *req, nr_stun_message *res)
   1.149 +{
   1.150 +    int _status;
   1.151 +#ifdef USE_STUN_PEDANTIC
   1.152 +    int r;
   1.153 +    nr_stun_attr_unknown_attributes unknown_attributes = { { 0 } };
   1.154 +    nr_stun_message_attribute *attr;
   1.155 +
   1.156 +    if (req->comprehension_required_unknown_attributes > 0) {
   1.157 +        nr_stun_form_error_response(req, res, 420, "Unknown Attributes");
   1.158 +
   1.159 +        TAILQ_FOREACH(attr, &req->attributes, entry) {
   1.160 +            if (attr->name == 0) {
   1.161 +                /* unrecognized attribute */
   1.162 +
   1.163 +                /* should never happen, but truncate if it ever were to occur */
   1.164 +                if (unknown_attributes.num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES)
   1.165 +                    break;
   1.166 +
   1.167 +                unknown_attributes.attribute[unknown_attributes.num_attributes++] = attr->type;
   1.168 +            }
   1.169 +        }
   1.170 +
   1.171 +        assert(req->comprehension_required_unknown_attributes + req->comprehension_optional_unknown_attributes == unknown_attributes.num_attributes);
   1.172 +
   1.173 +        if ((r=nr_stun_message_add_unknown_attributes_attribute(res, &unknown_attributes)))
   1.174 +            ABORT(R_ALREADY);
   1.175 +
   1.176 +        ABORT(R_ALREADY);
   1.177 +    }
   1.178 +#endif /* USE_STUN_PEDANTIC */
   1.179 +
   1.180 +    _status=0;
   1.181 +#ifdef USE_STUN_PEDANTIC
   1.182 +  abort:
   1.183 +#endif /* USE_STUN_PEDANTIC */
   1.184 +    return _status;
   1.185 +}
   1.186 +
   1.187 +/* draft-ietf-behave-rfc3489bis-10.txt S 7.3.2 */
   1.188 +int
   1.189 +nr_stun_process_indication(nr_stun_message *ind)
   1.190 +{
   1.191 +    int _status;
   1.192 +#ifdef USE_STUN_PEDANTIC
   1.193 +
   1.194 +    if (ind->comprehension_required_unknown_attributes > 0)
   1.195 +        ABORT(R_REJECTED);
   1.196 +#endif /* USE_STUN_PEDANTIC */
   1.197 +
   1.198 +    _status=0;
   1.199 +#ifdef USE_STUN_PEDANTIC
   1.200 +  abort:
   1.201 +#endif /* USE_STUN_PEDANTIC */
   1.202 +    return _status;
   1.203 +}
   1.204 +
   1.205 +/* RFC5389 S 7.3.3, except that we *also* allow a MAPPED_ADDRESS
   1.206 +   to compensate for a bug in Google's STUN server where it
   1.207 +   always returns MAPPED_ADDRESS.
   1.208 +
   1.209 +   Mozilla bug: 888274.
   1.210 + */
   1.211 +int
   1.212 +nr_stun_process_success_response(nr_stun_message *res)
   1.213 +{
   1.214 +    int _status;
   1.215 +
   1.216 +#ifdef USE_STUN_PEDANTIC
   1.217 +    if (res->comprehension_required_unknown_attributes > 0)
   1.218 +        ABORT(R_REJECTED);
   1.219 +#endif /* USE_STUN_PEDANTIC */
   1.220 +
   1.221 +    if (NR_STUN_GET_TYPE_METHOD(res->header.type) == NR_METHOD_BINDING) {
   1.222 +        if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0) &&
   1.223 +            ! nr_stun_message_has_attribute(res, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) {
   1.224 +            r_log(NR_LOG_STUN, LOG_WARNING, "Missing XOR-MAPPED-ADDRESS and MAPPED_ADDRESS");
   1.225 +            ABORT(R_REJECTED);
   1.226 +        }
   1.227 +    }
   1.228 +
   1.229 +    _status=0;
   1.230 + abort:
   1.231 +    return _status;
   1.232 +}
   1.233 +
   1.234 +/* draft-ietf-behave-rfc3489bis-10.txt S 7.3.4 */
   1.235 +int
   1.236 +nr_stun_process_error_response(nr_stun_message *res, UINT2 *error_code)
   1.237 +{
   1.238 +    int _status;
   1.239 +    nr_stun_message_attribute *attr;
   1.240 +
   1.241 +    if (res->comprehension_required_unknown_attributes > 0) {
   1.242 +        ABORT(R_REJECTED);
   1.243 +    }
   1.244 +
   1.245 +    if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_ERROR_CODE, &attr)) {
   1.246 +        r_log(NR_LOG_STUN, LOG_WARNING, "Missing ERROR-CODE");
   1.247 +        ABORT(R_REJECTED);
   1.248 +    }
   1.249 +
   1.250 +    *error_code = attr->u.error_code.number;
   1.251 +
   1.252 +    switch (attr->u.error_code.number / 100) {
   1.253 +    case 3:
   1.254 +        /* If the error code is 300 through 399, the client SHOULD consider
   1.255 +         * the transaction as failed unless the ALTERNATE-SERVER extension is
   1.256 +         * being used.  See Section 11. */
   1.257 +
   1.258 +        if (attr->u.error_code.number == 300) {
   1.259 +            if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_ALTERNATE_SERVER, 0)) {
   1.260 +                r_log(NR_LOG_STUN, LOG_WARNING, "Missing ALTERNATE-SERVER");
   1.261 +                ABORT(R_REJECTED);
   1.262 +            }
   1.263 +
   1.264 +            /* draft-ietf-behave-rfc3489bis-10.txt S 11 */
   1.265 +            if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
   1.266 +                r_log(NR_LOG_STUN, LOG_WARNING, "Missing MESSAGE-INTEGRITY");
   1.267 +                ABORT(R_REJECTED);
   1.268 +            }
   1.269 +
   1.270 +            ABORT(R_RETRY);
   1.271 +        }
   1.272 +
   1.273 +        ABORT(R_REJECTED);
   1.274 +        break;
   1.275 +
   1.276 +    case 4:
   1.277 +        /* If the error code is 400 through 499, the client declares the
   1.278 +         * transaction failed; in the case of 420 (Unknown Attribute), the
   1.279 +         * response should contain a UNKNOWN-ATTRIBUTES attribute that gives
   1.280 +         * additional information. */
   1.281 +        if (attr->u.error_code.number == 420)
   1.282 +            ABORT(R_REJECTED);
   1.283 +
   1.284 +        /* it may be possible to restart given the info that was received in
   1.285 +         * this response, so retry */
   1.286 +        ABORT(R_RETRY);
   1.287 +        break;
   1.288 +
   1.289 +    case 5:
   1.290 +        /* If the error code is 500 through 599, the client MAY resend the
   1.291 +         * request; clients that do so MUST limit the number of times they do
   1.292 +         * this. */
   1.293 +        /* let the retransmit mechanism handle resending the request */
   1.294 +        break;
   1.295 +
   1.296 +    default:
   1.297 +        ABORT(R_REJECTED);
   1.298 +        break;
   1.299 +    }
   1.300 +
   1.301 +    /* the spec says: "The client then does any processing specified by the authentication
   1.302 +     * mechanism (see Section 10).  This may result in a new transaction
   1.303 +     * attempt." -- but this is handled already elsewhere, so needn't be repeated
   1.304 +     * in this function */
   1.305 +
   1.306 +    _status=0;
   1.307 + abort:
   1.308 +    return _status;
   1.309 +}
   1.310 +
   1.311 +/* draft-ietf-behave-rfc3489bis-10.txt S 10.1.2 */
   1.312 +int
   1.313 +nr_stun_receive_request_or_indication_short_term_auth(nr_stun_message *msg,
   1.314 +                                                      nr_stun_message *res)
   1.315 +{
   1.316 +    int _status;
   1.317 +    nr_stun_message_attribute *attr;
   1.318 +
   1.319 +    switch (msg->header.magic_cookie) {
   1.320 +    default:
   1.321 +        /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   1.322 +        /* drop thru */
   1.323 +    case NR_STUN_MAGIC_COOKIE:
   1.324 +        if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
   1.325 +            nr_stun_form_error_response(msg, res, 400, "Missing MESSAGE-INTEGRITY");
   1.326 +            ABORT(R_ALREADY);
   1.327 +        }
   1.328 +
   1.329 +        if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_USERNAME, 0)) {
   1.330 +            nr_stun_form_error_response(msg, res, 400, "Missing USERNAME");
   1.331 +            ABORT(R_ALREADY);
   1.332 +        }
   1.333 +
   1.334 +        if (attr->u.message_integrity.unknown_user) {
   1.335 +            nr_stun_form_error_response(msg, res, 401, "Unrecognized USERNAME");
   1.336 +            ABORT(R_ALREADY);
   1.337 +        }
   1.338 +
   1.339 +        if (!attr->u.message_integrity.valid) {
   1.340 +            nr_stun_form_error_response(msg, res, 401, "Bad MESSAGE-INTEGRITY");
   1.341 +            ABORT(R_ALREADY);
   1.342 +        }
   1.343 +
   1.344 +        break;
   1.345 +
   1.346 +#ifdef USE_STUND_0_96
   1.347 +    case NR_STUN_MAGIC_COOKIE2:
   1.348 +        /* nothing to check in this case */
   1.349 +        break;
   1.350 +#endif /* USE_STUND_0_96 */
   1.351 +    }
   1.352 +
   1.353 +    _status=0;
   1.354 + abort:
   1.355 +    return _status;
   1.356 +}
   1.357 +
   1.358 +/* draft-ietf-behave-rfc3489bis-10.txt S 10.1.3 */
   1.359 +int
   1.360 +nr_stun_receive_response_short_term_auth(nr_stun_message *res)
   1.361 +{
   1.362 +    int _status;
   1.363 +    nr_stun_message_attribute *attr;
   1.364 +
   1.365 +    switch (res->header.magic_cookie) {
   1.366 +    default:
   1.367 +        /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   1.368 +        /* drop thru */
   1.369 +    case NR_STUN_MAGIC_COOKIE:
   1.370 +        if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
   1.371 +            r_log(NR_LOG_STUN, LOG_WARNING, "Missing MESSAGE-INTEGRITY");
   1.372 +            ABORT(R_REJECTED);
   1.373 +        }
   1.374 +
   1.375 +        if (!attr->u.message_integrity.valid) {
   1.376 +            r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY");
   1.377 +            ABORT(R_REJECTED);
   1.378 +        }
   1.379 +
   1.380 +        break;
   1.381 +
   1.382 +#ifdef USE_STUND_0_96
   1.383 +    case NR_STUN_MAGIC_COOKIE2:
   1.384 +        /* nothing to check in this case */
   1.385 +        break;
   1.386 +#endif /* USE_STUND_0_96 */
   1.387 +    }
   1.388 +
   1.389 +   _status=0;
   1.390 + abort:
   1.391 +     return _status;
   1.392 +}
   1.393 +
   1.394 +static int
   1.395 +nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res)
   1.396 +{
   1.397 +    int r,_status;
   1.398 +    char *realm = 0;
   1.399 +    char *nonce;
   1.400 +    UINT2 size;
   1.401 +
   1.402 +    if ((r=NR_reg_alloc_string(NR_STUN_REG_PREF_SERVER_REALM, &realm)))
   1.403 +        ABORT(r);
   1.404 +
   1.405 +    if ((r=nr_stun_message_add_realm_attribute(res, realm)))
   1.406 +        ABORT(r);
   1.407 +
   1.408 +    if (clnt) {
   1.409 +        if (strlen(clnt->nonce) < 1)
   1.410 +            new_nonce = 1;
   1.411 +
   1.412 +        if (new_nonce) {
   1.413 +            if (NR_reg_get_uint2(NR_STUN_REG_PREF_SERVER_NONCE_SIZE, &size))
   1.414 +                size = 48;
   1.415 +
   1.416 +            if (size > (sizeof(clnt->nonce) - 1))
   1.417 +                size = sizeof(clnt->nonce) - 1;
   1.418 +
   1.419 +            nr_random_alphanum(clnt->nonce, size);
   1.420 +            clnt->nonce[size] = '\0';
   1.421 +        }
   1.422 +
   1.423 +        nonce = clnt->nonce;
   1.424 +    }
   1.425 +    else {
   1.426 +        /* user is not known, so use a bogus nonce since there's no way to
   1.427 +         * store a good nonce with the client-specific data -- this nonce
   1.428 +         * will be recognized as stale if the client attempts another
   1.429 +         * request */
   1.430 +        nonce = "STALE";
   1.431 +    }
   1.432 +
   1.433 +    if ((r=nr_stun_message_add_nonce_attribute(res, nonce)))
   1.434 +        ABORT(r);
   1.435 +
   1.436 +    _status=0;
   1.437 + abort:
   1.438 +#ifdef USE_TURN
   1.439 +assert(_status == 0); /* TODO: !nn! cleanup after I reimplmement TURN */
   1.440 +#endif
   1.441 +    RFREE(realm);
   1.442 +    return _status;
   1.443 +}
   1.444 +
   1.445 +/* draft-ietf-behave-rfc3489bis-10.txt S 10.2.1 - 10.2.2 */
   1.446 +int
   1.447 +nr_stun_receive_request_long_term_auth(nr_stun_message *req, nr_stun_server_ctx *ctx, nr_stun_message *res)
   1.448 +{
   1.449 +    int r,_status;
   1.450 +    nr_stun_message_attribute *mi;
   1.451 +    nr_stun_message_attribute *n;
   1.452 +    nr_stun_server_client *clnt = 0;
   1.453 +
   1.454 +    switch (req->header.magic_cookie) {
   1.455 +    default:
   1.456 +        /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   1.457 +        /* drop thru */
   1.458 +    case NR_STUN_MAGIC_COOKIE:
   1.459 +        if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, 0)) {
   1.460 +            nr_stun_form_error_response(req, res, 400, "Missing USERNAME");
   1.461 +            nr_stun_add_realm_and_nonce(0, 0, res);
   1.462 +            ABORT(R_ALREADY);
   1.463 +        }
   1.464 +
   1.465 +        if ((r=nr_stun_get_message_client(ctx, req, &clnt))) {
   1.466 +            nr_stun_form_error_response(req, res, 401, "Unrecognized USERNAME");
   1.467 +            nr_stun_add_realm_and_nonce(0, 0, res);
   1.468 +            ABORT(R_ALREADY);
   1.469 +        }
   1.470 +
   1.471 +        if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, &mi)) {
   1.472 +            nr_stun_form_error_response(req, res, 401, "Missing MESSAGE-INTEGRITY");
   1.473 +            nr_stun_add_realm_and_nonce(0, clnt, res);
   1.474 +            ABORT(R_ALREADY);
   1.475 +        }
   1.476 +
   1.477 +        assert(!mi->u.message_integrity.unknown_user);
   1.478 +
   1.479 +        if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_REALM, 0)) {
   1.480 +            nr_stun_form_error_response(req, res, 400, "Missing REALM");
   1.481 +            ABORT(R_ALREADY);
   1.482 +        }
   1.483 +
   1.484 +        if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_NONCE, &n)) {
   1.485 +            nr_stun_form_error_response(req, res, 400, "Missing NONCE");
   1.486 +            ABORT(R_ALREADY);
   1.487 +        }
   1.488 +
   1.489 +        assert(sizeof(clnt->nonce) == sizeof(n->u.nonce));
   1.490 +        if (strncmp(clnt->nonce, n->u.nonce, sizeof(n->u.nonce))) {
   1.491 +            nr_stun_form_error_response(req, res, 438, "Stale NONCE");
   1.492 +            nr_stun_add_realm_and_nonce(1, clnt, res);
   1.493 +            ABORT(R_ALREADY);
   1.494 +        }
   1.495 +
   1.496 +        if (!mi->u.message_integrity.valid) {
   1.497 +            nr_stun_form_error_response(req, res, 401, "Bad MESSAGE-INTEGRITY");
   1.498 +            nr_stun_add_realm_and_nonce(0, clnt, res);
   1.499 +            ABORT(R_ALREADY);
   1.500 +        }
   1.501 +
   1.502 +        break;
   1.503 +
   1.504 +#ifdef USE_STUND_0_96
   1.505 +    case NR_STUN_MAGIC_COOKIE2:
   1.506 +        /* nothing to do in this case */
   1.507 +        break;
   1.508 +#endif /* USE_STUND_0_96 */
   1.509 +    }
   1.510 +
   1.511 +    _status=0;
   1.512 + abort:
   1.513 +
   1.514 +    return _status;
   1.515 +}
   1.516 +
   1.517 +/* draft-ietf-behave-rfc3489bis-10.txt S 10.2.3 */
   1.518 +int
   1.519 +nr_stun_receive_response_long_term_auth(nr_stun_message *res, nr_stun_client_ctx *ctx)
   1.520 +{
   1.521 +    int _status;
   1.522 +    nr_stun_message_attribute *attr;
   1.523 +
   1.524 +    switch (res->header.magic_cookie) {
   1.525 +    default:
   1.526 +        /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
   1.527 +        /* drop thru */
   1.528 +    case NR_STUN_MAGIC_COOKIE:
   1.529 +        if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_REALM, &attr)) {
   1.530 +            RFREE(ctx->realm);
   1.531 +            ctx->realm = r_strdup(attr->u.realm);
   1.532 +            if (!ctx->realm)
   1.533 +                ABORT(R_NO_MEMORY);
   1.534 +        }
   1.535 +        else {
   1.536 +            r_log(NR_LOG_STUN, LOG_WARNING, "Missing REALM");
   1.537 +            ABORT(R_REJECTED);
   1.538 +        }
   1.539 +
   1.540 +        if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_NONCE, &attr)) {
   1.541 +            RFREE(ctx->nonce);
   1.542 +            ctx->nonce = r_strdup(attr->u.nonce);
   1.543 +            if (!ctx->nonce)
   1.544 +                ABORT(R_NO_MEMORY);
   1.545 +        }
   1.546 +        else {
   1.547 +            r_log(NR_LOG_STUN, LOG_WARNING, "Missing NONCE");
   1.548 +            ABORT(R_REJECTED);
   1.549 +        }
   1.550 +
   1.551 +        if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
   1.552 +            if (!attr->u.message_integrity.valid) {
   1.553 +                r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY");
   1.554 +                ABORT(R_REJECTED);
   1.555 +            }
   1.556 +        }
   1.557 +
   1.558 +        break;
   1.559 +
   1.560 +#ifdef USE_STUND_0_96
   1.561 +    case NR_STUN_MAGIC_COOKIE2:
   1.562 +        /* nothing to check in this case */
   1.563 +        break;
   1.564 +#endif /* USE_STUND_0_96 */
   1.565 +    }
   1.566 +
   1.567 +    _status=0;
   1.568 + abort:
   1.569 +    return _status;
   1.570 +}
   1.571 +

mercurial