| File: | root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_server_ctx.cpp |
| Warning: | line 56, column 7 Potential leak of memory pointed to by 'ctx' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | Copyright (c) 2007, Adobe Systems, Incorporated | |||
| 3 | All rights reserved. | |||
| 4 | ||||
| 5 | Redistribution and use in source and binary forms, with or without | |||
| 6 | modification, are permitted provided that the following conditions are | |||
| 7 | met: | |||
| 8 | ||||
| 9 | * Redistributions of source code must retain the above copyright | |||
| 10 | notice, this list of conditions and the following disclaimer. | |||
| 11 | ||||
| 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. | |||
| 15 | ||||
| 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. | |||
| 19 | ||||
| 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 | */ | |||
| 32 | ||||
| 33 | #include <string.h> | |||
| 34 | #include <assert.h> | |||
| 35 | ||||
| 36 | #include "nr_api.h" | |||
| 37 | #include "stun.h" | |||
| 38 | ||||
| 39 | static int nr_stun_server_destroy_client(nr_stun_server_client *clnt); | |||
| 40 | static int nr_stun_server_send_response(nr_stun_server_ctx *ctx, nr_socket *sock, nr_transport_addr *peer_addr, nr_stun_message *res, nr_stun_server_client *clnt); | |||
| 41 | static int nr_stun_server_process_request_auth_checks(nr_stun_server_ctx *ctx, nr_stun_message *req, int auth_rule, nr_stun_message *res); | |||
| 42 | ||||
| 43 | ||||
| 44 | int nr_stun_server_ctx_create(char *label, nr_stun_server_ctx **ctxp) | |||
| 45 | { | |||
| 46 | int r,_status; | |||
| 47 | nr_stun_server_ctx *ctx=0; | |||
| 48 | ||||
| 49 | if ((r=nr_stun_startup())) | |||
| ||||
| 50 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 51 | ||||
| 52 | if(!(ctx=R_NEW(nr_stun_server_ctx)(nr_stun_server_ctx*)calloc(1,sizeof(nr_stun_server_ctx)))) | |||
| 53 | ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 54 | ||||
| 55 | if(!(ctx->label=strdup(label))) | |||
| 56 | ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| ||||
| 57 | ||||
| 58 | STAILQ_INIT(&ctx->clients)do { (((&ctx->clients))->stqh_first) = __null; (& ctx->clients)->stqh_last = &(((&ctx->clients ))->stqh_first); } while (0); | |||
| 59 | ||||
| 60 | *ctxp=ctx; | |||
| 61 | ||||
| 62 | _status=0; | |||
| 63 | abort: | |||
| 64 | return(_status); | |||
| 65 | } | |||
| 66 | ||||
| 67 | int nr_stun_server_ctx_destroy(nr_stun_server_ctx **ctxp) | |||
| 68 | { | |||
| 69 | nr_stun_server_ctx *ctx; | |||
| 70 | nr_stun_server_client *clnt1,*clnt2; | |||
| 71 | ||||
| 72 | if(!ctxp || !*ctxp) | |||
| 73 | return(0); | |||
| 74 | ||||
| 75 | ctx=*ctxp; | |||
| 76 | ||||
| 77 | STAILQ_FOREACH_SAFE(clnt1, &ctx->clients, entry, clnt2)for ((clnt1) = (((&ctx->clients))->stqh_first); (clnt1 ) && ((clnt2) = (((clnt1))->entry.stqe_next), 1); ( clnt1) = (clnt2)) { | |||
| 78 | nr_stun_server_destroy_client(clnt1); | |||
| 79 | } | |||
| 80 | ||||
| 81 | nr_stun_server_destroy_client(ctx->default_client); | |||
| 82 | ||||
| 83 | free(ctx->label); | |||
| 84 | free(ctx); | |||
| 85 | ||||
| 86 | return(0); | |||
| 87 | } | |||
| 88 | ||||
| 89 | static int nr_stun_server_client_create(nr_stun_server_ctx *ctx, const char *client_label, char *user, Data *pass, nr_stun_server_cb cb, void *cb_arg, nr_stun_server_client **clntp) | |||
| 90 | { | |||
| 91 | nr_stun_server_client *clnt=0; | |||
| 92 | int r,_status; | |||
| 93 | ||||
| 94 | if(!(clnt=R_NEW(nr_stun_server_client)(nr_stun_server_client*)calloc(1,sizeof(nr_stun_server_client )))) | |||
| 95 | ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 96 | ||||
| 97 | if(!(clnt->label=strdup(client_label))) | |||
| 98 | ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 99 | ||||
| 100 | if(!(clnt->username=strdup(user))) | |||
| 101 | ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 102 | ||||
| 103 | if(r=r_data_copy(&clnt->password,pass)) | |||
| 104 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 105 | ||||
| 106 | r_log(NR_LOG_STUN,LOG_DEBUG7,"STUN-SERVER(%s)/CLIENT(%s): Adding client for %s",ctx->label, client_label, user); | |||
| 107 | clnt->stun_server_cb=cb; | |||
| 108 | clnt->cb_arg=cb_arg; | |||
| 109 | ||||
| 110 | *clntp = clnt; | |||
| 111 | _status=0; | |||
| 112 | abort: | |||
| 113 | if(_status){ | |||
| 114 | nr_stun_server_destroy_client(clnt); | |||
| 115 | } | |||
| 116 | return(_status); | |||
| 117 | } | |||
| 118 | ||||
| 119 | int nr_stun_server_add_client(nr_stun_server_ctx *ctx, char *client_label, char *user, Data *pass, nr_stun_server_cb cb, void *cb_arg) | |||
| 120 | { | |||
| 121 | int r,_status; | |||
| 122 | nr_stun_server_client *clnt; | |||
| 123 | ||||
| 124 | if (r=nr_stun_server_client_create(ctx, client_label, user, pass, cb, cb_arg, &clnt)) | |||
| 125 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 126 | ||||
| 127 | STAILQ_INSERT_TAIL(&ctx->clients,clnt,entry)do { (((clnt))->entry.stqe_next) = __null; *(&ctx-> clients)->stqh_last = (clnt); (&ctx->clients)->stqh_last = &(((clnt))->entry.stqe_next); } while (0); | |||
| 128 | ||||
| 129 | _status=0; | |||
| 130 | abort: | |||
| 131 | return(_status); | |||
| 132 | } | |||
| 133 | ||||
| 134 | int nr_stun_server_add_default_client(nr_stun_server_ctx *ctx, char *ufrag, Data *pass, nr_stun_server_cb cb, void *cb_arg) | |||
| 135 | { | |||
| 136 | int r,_status; | |||
| 137 | nr_stun_server_client *clnt; | |||
| 138 | ||||
| 139 | assert(!ctx->default_client)(static_cast <bool> (!ctx->default_client) ? void (0 ) : __assert_fail ("!ctx->default_client", __builtin_FILE ( ), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | |||
| 140 | if (ctx->default_client) | |||
| 141 | ABORT(R_INTERNAL)do { int _r=3; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 142 | ||||
| 143 | if (r=nr_stun_server_client_create(ctx, "default_client", ufrag, pass, cb, cb_arg, &clnt)) | |||
| 144 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 145 | ||||
| 146 | ctx->default_client = clnt; | |||
| 147 | ||||
| 148 | _status=0; | |||
| 149 | abort: | |||
| 150 | return(_status); | |||
| 151 | } | |||
| 152 | ||||
| 153 | int nr_stun_server_remove_client(nr_stun_server_ctx *ctx, void *cb_arg) | |||
| 154 | { | |||
| 155 | nr_stun_server_client *clnt1,*clnt2; | |||
| 156 | int found = 0; | |||
| 157 | ||||
| 158 | STAILQ_FOREACH_SAFE(clnt1, &ctx->clients, entry, clnt2)for ((clnt1) = (((&ctx->clients))->stqh_first); (clnt1 ) && ((clnt2) = (((clnt1))->entry.stqe_next), 1); ( clnt1) = (clnt2)) { | |||
| 159 | if(clnt1->cb_arg == cb_arg) { | |||
| 160 | STAILQ_REMOVE(&ctx->clients, clnt1, nr_stun_server_client_, entry)do { if ((((&ctx->clients))->stqh_first) == (clnt1) ) { do { if ((((((&ctx->clients)))->stqh_first) = ( (((((&ctx->clients)))->stqh_first))->entry.stqe_next )) == __null) ((&ctx->clients))->stqh_last = &( (((&ctx->clients)))->stqh_first); } while (0); } else { struct nr_stun_server_client_ *curelm = (((&ctx->clients ))->stqh_first); while (((curelm)->entry.stqe_next) != ( clnt1)) curelm = ((curelm)->entry.stqe_next); if ((((curelm )->entry.stqe_next) = ((((curelm)->entry.stqe_next))-> entry.stqe_next)) == __null) (&ctx->clients)->stqh_last = &(((curelm))->entry.stqe_next); } } while (0); | |||
| 161 | nr_stun_server_destroy_client(clnt1); | |||
| 162 | found++; | |||
| 163 | } | |||
| 164 | } | |||
| 165 | ||||
| 166 | if (!found) | |||
| 167 | ERETURN(R_NOT_FOUND)do {int _r=2; if(!_r) _r=-1; return(_r);} while(0); | |||
| 168 | ||||
| 169 | return 0; | |||
| 170 | } | |||
| 171 | ||||
| 172 | static int nr_stun_server_get_password(void *arg, nr_stun_message *msg, Data **password) | |||
| 173 | { | |||
| 174 | int _status; | |||
| 175 | nr_stun_server_ctx *ctx = (nr_stun_server_ctx*)arg; | |||
| 176 | nr_stun_server_client *clnt = 0; | |||
| 177 | nr_stun_message_attribute *username_attribute; | |||
| 178 | ||||
| 179 | if ((nr_stun_get_message_client(ctx, msg, &clnt))) { | |||
| 180 | if (! nr_stun_message_has_attribute(msg, NR_STUN_ATTR_USERNAME0x0006, &username_attribute)) { | |||
| 181 | r_log(NR_LOG_STUN,LOG_WARNING4,"STUN-SERVER(%s): Missing Username",ctx->label); | |||
| 182 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 183 | } | |||
| 184 | ||||
| 185 | /* Although this is an exceptional condition, we'll already have seen a | |||
| 186 | * NOTICE-level log message about the unknown user, so additional log | |||
| 187 | * messages at any level higher than DEBUG are unnecessary. */ | |||
| 188 | ||||
| 189 | r_log(NR_LOG_STUN,LOG_DEBUG7,"STUN-SERVER(%s): Unable to find password for unknown user: %s",ctx->label,username_attribute->u.username); | |||
| 190 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 191 | } | |||
| 192 | ||||
| 193 | *password = &clnt->password; | |||
| 194 | ||||
| 195 | _status=0; | |||
| 196 | abort: | |||
| 197 | return(_status); | |||
| 198 | } | |||
| 199 | ||||
| 200 | int nr_stun_server_process_request_auth_checks(nr_stun_server_ctx *ctx, nr_stun_message *req, int auth_rule, nr_stun_message *res) | |||
| 201 | { | |||
| 202 | int r,_status; | |||
| 203 | ||||
| 204 | if (nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY0x0008, 0) | |||
| 205 | || !(auth_rule & NR_STUN_AUTH_RULE_OPTIONAL(1<<0))) { | |||
| 206 | /* favor long term credentials over short term, if both are supported */ | |||
| 207 | ||||
| 208 | if (auth_rule & NR_STUN_AUTH_RULE_LONG_TERM(1<<9)) { | |||
| 209 | if ((r=nr_stun_receive_request_long_term_auth(req, ctx, res))) | |||
| 210 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 211 | } | |||
| 212 | else if (auth_rule & NR_STUN_AUTH_RULE_SHORT_TERM(1<<8)) { | |||
| 213 | if ((r=nr_stun_receive_request_or_indication_short_term_auth(req, res))) | |||
| 214 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 215 | } | |||
| 216 | } | |||
| 217 | ||||
| 218 | _status=0; | |||
| 219 | abort: | |||
| 220 | return(_status); | |||
| 221 | } | |||
| 222 | ||||
| 223 | int nr_stun_server_process_request(nr_stun_server_ctx *ctx, nr_socket *sock, char *msg, int len, nr_transport_addr *peer_addr, int auth_rule) | |||
| 224 | { | |||
| 225 | int r,_status; | |||
| 226 | char string[256]; | |||
| 227 | nr_stun_message *req = 0; | |||
| 228 | nr_stun_message *res = 0; | |||
| 229 | nr_stun_server_client *clnt = 0; | |||
| 230 | nr_stun_server_request info; | |||
| 231 | int error; | |||
| 232 | int dont_free = 0; | |||
| 233 | nr_transport_addr my_addr; | |||
| 234 | ||||
| 235 | if ((r=nr_socket_getaddr(sock, &my_addr))) { | |||
| 236 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 237 | } | |||
| 238 | ||||
| 239 | r_log(NR_LOG_STUN,LOG_DEBUG7,"STUN-SERVER(%s): Received(my_addr=%s,peer_addr=%s)",ctx->label,my_addr.as_string,peer_addr->as_string); | |||
| 240 | ||||
| 241 | snprintf(string, sizeof(string)-1, "STUN-SERVER(%s): Received ", ctx->label); | |||
| 242 | r_dump(NR_LOG_STUN, LOG_DEBUG7, string, (char*)msg, len); | |||
| 243 | ||||
| 244 | memset(&info,0,sizeof(info)); | |||
| 245 | ||||
| 246 | if ((r=nr_stun_message_create2(&req, (UCHAR*)msg, len))) | |||
| 247 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 248 | ||||
| 249 | if ((r=nr_stun_message_create(&res))) | |||
| 250 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 251 | ||||
| 252 | if ((r=nr_stun_decode_message(req, nr_stun_server_get_password, ctx))) { | |||
| 253 | /* RFC5389 S 7.3 says "If any errors are detected, the message is | |||
| 254 | * silently discarded." */ | |||
| 255 | #ifndef USE_STUN_PEDANTIC1 | |||
| 256 | /* ... but that seems like a bad idea, at least return a 400 so | |||
| 257 | * that the server isn't a black hole to the client */ | |||
| 258 | nr_stun_form_error_response(req, res, 400, "Bad Request - Failed to decode request"); | |||
| 259 | ABORT(R_ALREADY)do { int _r=4; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 260 | #endif /* USE_STUN_PEDANTIC */ | |||
| 261 | ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while (0); | |||
| 262 | } | |||
| 263 | ||||
| 264 | if ((r=nr_stun_receive_message(0, req))) { | |||
| 265 | /* RFC5389 S 7.3 says "If any errors are detected, the message is | |||
| 266 | * silently discarded." */ | |||
| 267 | #ifndef USE_STUN_PEDANTIC1 | |||
| 268 | /* ... but that seems like a bad idea, at least return a 400 so | |||
| 269 | * that the server isn't a black hole to the client */ | |||
| 270 | nr_stun_form_error_response(req, res, 400, "Bad Request - Section 7.3 check failed"); | |||
| 271 | ABORT(R_ALREADY)do { int _r=4; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 272 | #endif /* USE_STUN_PEDANTIC */ | |||
| 273 | ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while (0); | |||
| 274 | } | |||
| 275 | ||||
| 276 | if (NR_STUN_GET_TYPE_CLASS(req->header.type)((((req->header.type) >> 7) & 0x002) | (((req-> header.type) >> 4) & 0x001)) != NR_CLASS_REQUEST0x0 | |||
| 277 | && NR_STUN_GET_TYPE_CLASS(req->header.type)((((req->header.type) >> 7) & 0x002) | (((req-> header.type) >> 4) & 0x001)) != NR_CLASS_INDICATION0x1) { | |||
| 278 | r_log(NR_LOG_STUN,LOG_WARNING4,"STUN-SERVER(%s): Illegal message type: %04x",ctx->label,req->header.type); | |||
| 279 | /* RFC5389 S 7.3 says "If any errors are detected, the message is | |||
| 280 | * silently discarded." */ | |||
| 281 | #ifndef USE_STUN_PEDANTIC1 | |||
| 282 | /* ... but that seems like a bad idea, at least return a 400 so | |||
| 283 | * that the server isn't a black hole to the client */ | |||
| 284 | nr_stun_form_error_response(req, res, 400, "Bad Request - Unsupported message type"); | |||
| 285 | ABORT(R_ALREADY)do { int _r=4; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 286 | #endif /* USE_STUN_PEDANTIC */ | |||
| 287 | ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while (0); | |||
| 288 | } | |||
| 289 | ||||
| 290 | /* "The STUN agent then does any checks that are required by a | |||
| 291 | * authentication mechanism that the usage has specified" */ | |||
| 292 | if ((r=nr_stun_server_process_request_auth_checks(ctx, req, auth_rule, res))) | |||
| 293 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 294 | ||||
| 295 | if (NR_STUN_GET_TYPE_CLASS(req->header.type)((((req->header.type) >> 7) & 0x002) | (((req-> header.type) >> 4) & 0x001)) == NR_CLASS_INDICATION0x1) { | |||
| 296 | if ((r=nr_stun_process_indication(req))) | |||
| 297 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 298 | } | |||
| 299 | else { | |||
| 300 | if ((r=nr_stun_process_request(req, res))) | |||
| 301 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 302 | } | |||
| 303 | ||||
| 304 | assert(res->header.type == 0)(static_cast <bool> (res->header.type == 0) ? void ( 0) : __assert_fail ("res->header.type == 0", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | |||
| 305 | ||||
| 306 | clnt = 0; | |||
| 307 | if (NR_STUN_GET_TYPE_CLASS(req->header.type)((((req->header.type) >> 7) & 0x002) | (((req-> header.type) >> 4) & 0x001)) == NR_CLASS_REQUEST0x0) { | |||
| 308 | if ((nr_stun_get_message_client(ctx, req, &clnt))) { | |||
| 309 | if ((r=nr_stun_form_success_response(req, peer_addr, 0, res))) | |||
| 310 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 311 | } | |||
| 312 | else { | |||
| 313 | if ((r=nr_stun_form_success_response(req, peer_addr, &clnt->password, res))) | |||
| 314 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 315 | } | |||
| 316 | } | |||
| 317 | ||||
| 318 | if(clnt && clnt->stun_server_cb){ | |||
| 319 | r_log(NR_LOG_STUN,LOG_DEBUG7,"Entering STUN server callback"); | |||
| 320 | ||||
| 321 | /* Set up the info */ | |||
| 322 | if(r=nr_transport_addr_copy(&info.src_addr,peer_addr)) | |||
| 323 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 324 | ||||
| 325 | info.request = req; | |||
| 326 | info.response = res; | |||
| 327 | ||||
| 328 | error = 0; | |||
| 329 | dont_free = 0; | |||
| 330 | if (clnt->stun_server_cb(clnt->cb_arg,ctx,sock,&info,&dont_free,&error)) { | |||
| 331 | if (error == 0) | |||
| 332 | error = 500; | |||
| 333 | ||||
| 334 | nr_stun_form_error_response(req, res, error, "ICE Failure"); | |||
| 335 | ABORT(R_ALREADY)do { int _r=4; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 336 | } | |||
| 337 | } | |||
| 338 | ||||
| 339 | _status=0; | |||
| 340 | abort: | |||
| 341 | if (!res) | |||
| 342 | goto skip_response; | |||
| 343 | ||||
| 344 | if (NR_STUN_GET_TYPE_CLASS(req->header.type)((((req->header.type) >> 7) & 0x002) | (((req-> header.type) >> 4) & 0x001)) == NR_CLASS_INDICATION0x1) | |||
| 345 | goto skip_response; | |||
| 346 | ||||
| 347 | /* Now respond */ | |||
| 348 | ||||
| 349 | if (_status != 0 && ! nr_stun_message_has_attribute(res, NR_STUN_ATTR_ERROR_CODE0x0009, 0)) | |||
| 350 | nr_stun_form_error_response(req, res, 500, "Failed to specify error"); | |||
| 351 | ||||
| 352 | if ((r=nr_stun_server_send_response(ctx, sock, peer_addr, res, clnt))) { | |||
| 353 | r_log(NR_LOG_STUN,LOG_ERR3,"STUN-SERVER(label=%s): Failed sending response (my_addr=%s,peer_addr=%s)",ctx->label,my_addr.as_string,peer_addr->as_string); | |||
| 354 | _status = R_FAILED10; | |||
| 355 | } | |||
| 356 | ||||
| 357 | if (0) { | |||
| 358 | skip_response: | |||
| 359 | _status = 0; | |||
| 360 | } | |||
| 361 | ||||
| 362 | if (!dont_free) { | |||
| 363 | nr_stun_message_destroy(&res); | |||
| 364 | nr_stun_message_destroy(&req); | |||
| 365 | } | |||
| 366 | ||||
| 367 | return(_status); | |||
| 368 | } | |||
| 369 | ||||
| 370 | static int nr_stun_server_send_response(nr_stun_server_ctx *ctx, nr_socket *sock, nr_transport_addr *peer_addr, nr_stun_message *res, nr_stun_server_client *clnt) | |||
| 371 | { | |||
| 372 | int r,_status; | |||
| 373 | char string[256]; | |||
| 374 | nr_transport_addr my_addr; | |||
| 375 | ||||
| 376 | if ((r=nr_socket_getaddr(sock, &my_addr))) { | |||
| 377 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 378 | } | |||
| 379 | ||||
| 380 | r_log(NR_LOG_STUN,LOG_DEBUG7,"STUN-SERVER(label=%s): Sending(my_addr=%s,peer_addr=%s)",ctx->label,my_addr.as_string,peer_addr->as_string); | |||
| 381 | ||||
| 382 | if ((r=nr_stun_encode_message(res))) { | |||
| 383 | /* should never happen */ | |||
| 384 | r_log(NR_LOG_STUN,LOG_ERR3,"STUN-SERVER(label=%s): Unable to encode message", ctx->label); | |||
| 385 | } | |||
| 386 | else { | |||
| 387 | snprintf(string, sizeof(string)-1, "STUN(%s): Sending to %s ", ctx->label, peer_addr->as_string); | |||
| 388 | r_dump(NR_LOG_STUN, LOG_DEBUG7, string, (char*)res->buffer, res->length); | |||
| 389 | ||||
| 390 | if(r=nr_socket_sendto(sock,res->buffer,res->length,0,peer_addr)) | |||
| 391 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 392 | } | |||
| 393 | ||||
| 394 | _status=0; | |||
| 395 | abort: | |||
| 396 | return(_status); | |||
| 397 | } | |||
| 398 | ||||
| 399 | static int nr_stun_server_destroy_client(nr_stun_server_client *clnt) | |||
| 400 | { | |||
| 401 | if (!clnt) | |||
| 402 | return 0; | |||
| 403 | ||||
| 404 | free(clnt->label); | |||
| 405 | free(clnt->username); | |||
| 406 | r_data_zfree(&clnt->password); | |||
| 407 | ||||
| 408 | free(clnt); | |||
| 409 | return(0); | |||
| 410 | } | |||
| 411 | ||||
| 412 | int nr_stun_get_message_client(nr_stun_server_ctx *ctx, nr_stun_message *req, nr_stun_server_client **out) | |||
| 413 | { | |||
| 414 | int _status; | |||
| 415 | nr_stun_message_attribute *attr; | |||
| 416 | nr_stun_server_client *clnt=0; | |||
| 417 | ||||
| 418 | if (! nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME0x0006, &attr)) { | |||
| 419 | r_log(NR_LOG_STUN,LOG_WARNING4,"STUN-SERVER(%s): Missing Username",ctx->label); | |||
| 420 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 421 | } | |||
| 422 | ||||
| 423 | STAILQ_FOREACH(clnt, &ctx->clients, entry)for((clnt) = (((&ctx->clients))->stqh_first); (clnt ); (clnt) = (((clnt))->entry.stqe_next)) { | |||
| 424 | if (!strncmp(clnt->username, attr->u.username, | |||
| 425 | sizeof(attr->u.username))) | |||
| 426 | break; | |||
| 427 | } | |||
| 428 | ||||
| 429 | if (!clnt && ctx->default_client) { | |||
| 430 | /* If we can't find a specific client see if this matches the default, | |||
| 431 | which means that the username starts with our ufrag. | |||
| 432 | */ | |||
| 433 | char *colon = strchr(attr->u.username, ':'); | |||
| 434 | if (colon && !strncmp(ctx->default_client->username, | |||
| 435 | attr->u.username, | |||
| 436 | colon - attr->u.username)) { | |||
| 437 | clnt = ctx->default_client; | |||
| 438 | r_log(NR_LOG_STUN,LOG_NOTICE5,"STUN-SERVER(%s): Falling back to default client, username=: %s",ctx->label,attr->u.username); | |||
| 439 | } | |||
| 440 | } | |||
| 441 | ||||
| 442 | if (!clnt) { | |||
| 443 | r_log(NR_LOG_STUN,LOG_WARNING4,"STUN-SERVER(%s): Request from unknown user: %s",ctx->label,attr->u.username); | |||
| 444 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); | |||
| 445 | } | |||
| 446 | ||||
| 447 | *out = clnt; | |||
| 448 | ||||
| 449 | _status=0; | |||
| 450 | abort: | |||
| 451 | return(_status); | |||
| 452 | } | |||
| 453 |