diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 82a8519d03c4a494185c725097d52f1184debfc4..eb26020f3b0bd9af9c410af7d4adc41ee549798a 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1009,6 +1009,11 @@ static struct ao2_container *threadt; static struct ao2_container *peers; static struct ao2_container *peers_by_ip; +/*! \brief A bogus peer, to be used when authentication should fail */ +static struct sip_peer *bogus_peer; +/*! \brief We can recognise the bogus peer by this invalid MD5 hash */ +#define BOGUS_PEER_MD5SECRET "intentionally_invalid_md5_string" + /*! \brief The register list: Other SIP proxies we register with and receive calls from */ static struct ast_register_list { ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry); @@ -1157,7 +1162,7 @@ static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale); static int transmit_provisional_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, int with_sdp); static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable); -static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable); +static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable); static int transmit_request(struct sip_pvt *p, int sipmethod, uint32_t seqno, enum xmittype reliable, int newbranch); static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, uint32_t seqno, enum xmittype reliable, int newbranch); static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_type publish_type, const char * const explicit_uri); @@ -16479,6 +16484,7 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request * char a1_hash[256]; char resp_hash[256]=""; char *c; + int is_bogus_peer = 0; int wrongnonce = FALSE; int good_response; const char *usednonce = p->nonce; @@ -16550,8 +16556,14 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request * sip_digest_parser(c, keys); + /* We cannot rely on the bogus_peer having a bad md5 value. Someone could + * use it to construct valid auth. */ + if (md5secret && strcmp(md5secret, BOGUS_PEER_MD5SECRET) == 0) { + is_bogus_peer = 1; + } + /* Verify that digest username matches the username we auth as */ - if (strcmp(username, keys[K_USER].s)) { + if (strcmp(username, keys[K_USER].s) && !is_bogus_peer) { ast_log(LOG_WARNING, "username mismatch, have <%s>, digest has <%s>\n", username, keys[K_USER].s); /* Oops, we're trying something here */ @@ -16590,7 +16602,8 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request * } good_response = keys[K_RESP].s && - !strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash)); + !strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash)) && + !is_bogus_peer; /* lastly, check that the peer isn't the fake peer */ if (wrongnonce) { if (good_response) { if (sipdebug) @@ -16821,13 +16834,13 @@ static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_inf /*! \brief Send a fake 401 Unauthorized response when the administrator wants to hide the names of local devices from fishers */ -static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable) +static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable) { /* We have to emulate EXACTLY what we'd get with a good peer * and a bad password, or else we leak information. */ - const char *response = "407 Proxy Authentication Required"; - const char *reqheader = "Proxy-Authorization"; - const char *respheader = "Proxy-Authenticate"; + const char *response = "401 Unauthorized"; + const char *reqheader = "Authorization"; + const char *respheader = "WWW-Authenticate"; const char *authtoken; struct ast_str *buf; char *c; @@ -16842,36 +16855,31 @@ static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct [K_LAST] = { NULL, NULL} }; - if (sipmethod == SIP_REGISTER || sipmethod == SIP_SUBSCRIBE) { - response = "401 Unauthorized"; - reqheader = "Authorization"; - respheader = "WWW-Authenticate"; - } authtoken = sip_get_header(req, reqheader); if (req->ignore && !ast_strlen_zero(p->nonce) && ast_strlen_zero(authtoken)) { /* This is a retransmitted invite/register/etc, don't reconstruct authentication * information */ - transmit_response_with_auth(p, response, req, p->nonce, 0, respheader, 0); + transmit_response_with_auth(p, response, req, p->nonce, reliable, respheader, 0); /* Schedule auto destroy in 32 seconds (according to RFC 3261) */ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); return; } else if (ast_strlen_zero(p->nonce) || ast_strlen_zero(authtoken)) { /* We have no auth, so issue challenge and request authentication */ build_nonce(p, 1); - transmit_response_with_auth(p, response, req, p->nonce, 0, respheader, 0); + transmit_response_with_auth(p, response, req, p->nonce, reliable, respheader, 0); /* Schedule auto destroy in 32 seconds */ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); return; } if (!(buf = ast_str_thread_get(&check_auth_buf, CHECK_AUTH_BUF_INITLEN))) { - transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); + __transmit_response(p, "403 Forbidden", &p->initreq, reliable); return; } /* Make a copy of the response and parse it */ if (ast_str_set(&buf, 0, "%s", authtoken) == AST_DYNSTR_BUILD_FAILED) { - transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); + __transmit_response(p, "403 Forbidden", &p->initreq, reliable); return; } @@ -16909,7 +16917,7 @@ static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct /* Schedule auto destroy in 32 seconds */ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); } else { - transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); + __transmit_response(p, "403 Forbidden", &p->initreq, reliable); } } @@ -17019,7 +17027,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock if (!AST_LIST_EMPTY(&domain_list)) { if (!check_sip_domain(domain, NULL, 0)) { if (sip_cfg.alwaysauthreject) { - transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE); + transmit_fake_auth_response(p, &p->initreq, XMIT_UNRELIABLE); } else { transmit_response(p, "404 Not found (unknown domain)", &p->initreq); } @@ -17046,6 +17054,13 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock } peer = sip_find_peer(name, NULL, TRUE, FINDPEERS, FALSE, 0); + /* If we don't want username disclosure, use the bogus_peer when a user + * is not found. */ + if (!peer && sip_cfg.alwaysauthreject && sip_cfg.autocreatepeer == AUTOPEERS_DISABLED) { + peer = bogus_peer; + sip_ref_peer(peer, "register_verify: ref the bogus_peer"); + } + if (!(peer && ast_apply_acl(peer->acl, addr, "SIP Peer ACL: "))) { /* Peer fails ACL check */ if (peer) { @@ -17137,7 +17152,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock switch (parse_register_contact(p, peer, req)) { case PARSE_REGISTER_DENIED: ast_log(LOG_WARNING, "Registration denied because of contact ACL\n"); - transmit_response_with_date(p, "403 Forbidden (ACL)", req); + transmit_response_with_date(p, "403 Forbidden", req); res = 0; break; case PARSE_REGISTER_FAILED: @@ -17177,7 +17192,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock switch (res) { case AUTH_SECRET_FAILED: /* Wrong password in authentication. Go away, don't try again until you fixed it */ - transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); + transmit_response(p, "403 Forbidden", &p->initreq); if (global_authfailureevents) { const char *peer_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr)); const char *peer_port = ast_strdupa(ast_sockaddr_stringify_port(addr)); @@ -17200,7 +17215,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock case AUTH_PEER_NOT_DYNAMIC: case AUTH_ACL_FAILED: if (sip_cfg.alwaysauthreject) { - transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE); + transmit_fake_auth_response(p, &p->initreq, XMIT_UNRELIABLE); if (global_authfailureevents) { const char *peer_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr)); const char *peer_port = ast_strdupa(ast_sockaddr_stringify_port(addr)); @@ -18239,7 +18254,19 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, ast_verbose("No matching peer for '%s' from '%s'\n", of, ast_sockaddr_stringify(&p->recv)); } - return AUTH_DONT_KNOW; + + /* If you don't mind, we can return 404s for devices that do + * not exist: username disclosure. If we allow guests, there + * is no way around that. */ + if (sip_cfg.allowguest || !sip_cfg.alwaysauthreject) { + return AUTH_DONT_KNOW; + } + + /* If you do mind, we use a peer that will never authenticate. + * This ensures that we follow the same code path as regular + * auth: less chance for username disclosure. */ + peer = bogus_peer; + sip_ref_peer(peer, "sip_ref_peer: check_peer_ok: must ref bogus_peer so unreffing it does not fail"); } /* build_peer, called through sip_find_peer, is not able to check the @@ -18262,9 +18289,10 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, sip_unref_peer(peer, "sip_unref_peer: check_peer_ok: from sip_find_peer call, early return of AUTH_ACL_FAILED"); return AUTH_ACL_FAILED; } - if (debug) + if (debug && peer != bogus_peer) { ast_verbose("Found peer '%s' for '%s' from %s\n", peer->name, of, ast_sockaddr_stringify(&p->recv)); + } /* XXX what about p->prefs = peer->prefs; ? */ /* Set Frame packetization */ @@ -18547,8 +18575,6 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ } else { res = AUTH_RTP_FAILED; } - } else if (sip_cfg.alwaysauthreject) { - res = AUTH_FAKE_AUTH; /* reject with fake authorization request */ } else { res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */ } @@ -18683,13 +18709,8 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a return; } if (res < 0) { /* Something failed in authentication */ - if (res == AUTH_FAKE_AUTH) { - ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From")); - transmit_fake_auth_response(p, SIP_MESSAGE, req, XMIT_UNRELIABLE); - } else { - ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From")); - transmit_response(p, "403 Forbidden", req); - } + ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From")); + transmit_response(p, "403 Forbidden", req); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); return; } @@ -24847,13 +24868,8 @@ static int handle_request_options(struct sip_pvt *p, struct sip_request *req, st return 0; } if (res < 0) { /* Something failed in authentication */ - if (res == AUTH_FAKE_AUTH) { - ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From")); - transmit_fake_auth_response(p, SIP_OPTIONS, req, XMIT_UNRELIABLE); - } else { - ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From")); - transmit_response(p, "403 Forbidden", req); - } + ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From")); + transmit_response(p, "403 Forbidden", req); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); return 0; } @@ -25498,13 +25514,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str goto request_invite_cleanup; } if (res < 0) { /* Something failed in authentication */ - if (res == AUTH_FAKE_AUTH) { - ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From")); - transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE); - } else { - ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From")); - transmit_response_reliable(p, "403 Forbidden", req); - } + ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From")); + transmit_response_reliable(p, "403 Forbidden", req); p->invitestate = INV_COMPLETED; sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); goto request_invite_cleanup; @@ -27547,18 +27558,13 @@ static int handle_request_publish(struct sip_pvt *p, struct sip_request *req, st return -1; } - auth_result = check_user(p, req, SIP_PUBLISH, uri, XMIT_RELIABLE, addr); + auth_result = check_user(p, req, SIP_PUBLISH, uri, XMIT_UNRELIABLE, addr); if (auth_result == AUTH_CHALLENGE_SENT) { p->lastinvite = seqno; return 0; } else if (auth_result < 0) { - if (auth_result == AUTH_FAKE_AUTH) { - ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From")); - transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE); - } else { - ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From")); - transmit_response_reliable(p, "403 Forbidden", req); - } + ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From")); + transmit_response(p, "403 Forbidden", req); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); ast_string_field_set(p, theirtag, NULL); return 0; @@ -27770,19 +27776,14 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, * use if !req->ignore, because then we'll end up sending * a 200 OK if someone retransmits without sending auth */ if (p->subscribed == NONE || resubscribe) { - res = check_user_full(p, req, SIP_SUBSCRIBE, e, 0, addr, &authpeer); + res = check_user_full(p, req, SIP_SUBSCRIBE, e, XMIT_UNRELIABLE, addr, &authpeer); /* if an authentication response was sent, we are done here */ if (res == AUTH_CHALLENGE_SENT) /* authpeer = NULL here */ return 0; if (res != AUTH_SUCCESSFUL) { - if (res == AUTH_FAKE_AUTH) { - ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From")); - transmit_fake_auth_response(p, SIP_SUBSCRIBE, req, XMIT_UNRELIABLE); - } else { - ast_log(LOG_NOTICE, "Failed to authenticate device %s for SUBSCRIBE\n", sip_get_header(req, "From")); - transmit_response_reliable(p, "403 Forbidden", req); - } + ast_log(LOG_NOTICE, "Failed to authenticate device %s for SUBSCRIBE\n", sip_get_header(req, "From")); + transmit_response(p, "403 Forbidden", req); pvt_set_needdestroy(p, "authentication failed"); return 0; @@ -33315,6 +33316,7 @@ static int sip_do_reload(enum channelreloadreason reason) /*! \brief Force reload of module from cli */ static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + static struct sip_peer *tmp_peer, *new_peer; switch (cmd) { case CLI_INIT: @@ -33337,6 +33339,18 @@ static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a ast_mutex_unlock(&sip_reload_lock); restart_monitor(); + tmp_peer = bogus_peer; + /* Create new bogus peer possibly with new global settings. */ + if ((new_peer = temp_peer("(bogus_peer)"))) { + ast_string_field_set(new_peer, md5secret, BOGUS_PEER_MD5SECRET); + ast_clear_flag(&new_peer->flags[0], SIP_INSECURE); + bogus_peer = new_peer; + ao2_t_ref(tmp_peer, -1, "unref the old bogus_peer during reload"); + } else { + ast_log(LOG_ERROR, "Could not update the fake authentication peer.\n"); + /* You probably have bigger (memory?) issues to worry about though.. */ + } + return CLI_SUCCESS; } @@ -34564,6 +34578,17 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } + /* Initialize bogus peer. Can be done first after reload_config() */ + if (!(bogus_peer = temp_peer("(bogus_peer)"))) { + ast_log(LOG_ERROR, "Unable to create bogus_peer for authentication\n"); + io_context_destroy(io); + ast_sched_context_destroy(sched); + return AST_MODULE_LOAD_FAILURE; + } + /* Make sure the auth will always fail. */ + ast_string_field_set(bogus_peer, md5secret, BOGUS_PEER_MD5SECRET); + ast_clear_flag(&bogus_peer->flags[0], SIP_INSECURE); + /* Prepare the version that does not require DTMF BEGIN frames. * We need to use tricks such as memcpy and casts because the variable * has const fields. @@ -34579,6 +34604,7 @@ static int load_module(void) /* Make sure we can register our sip channel type */ if (ast_channel_register(&sip_tech)) { ast_log(LOG_ERROR, "Unable to register channel type 'SIP'\n"); + ao2_t_ref(bogus_peer, -1, "unref the bogus_peer"); io_context_destroy(io); ast_sched_context_destroy(sched); return AST_MODULE_LOAD_FAILURE; @@ -34841,6 +34867,8 @@ static int unload_module(void) ast_debug(2, "TCP/TLS thread container did not become empty :(\n"); } + ao2_t_ref(bogus_peer, -1, "unref the bogus_peer"); + ao2_t_ref(peers, -1, "unref the peers table"); ao2_t_ref(peers_by_ip, -1, "unref the peers_by_ip table"); ao2_t_ref(dialogs, -1, "unref the dialogs table"); diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 6eb2f29a530832f95da92161e52db8b128b6cf56..e8f629b22883ec1ad32c264716293d0b5eebd4f3 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -507,7 +507,6 @@ enum check_auth_result { AUTH_SECRET_FAILED = -1, AUTH_USERNAME_MISMATCH = -2, AUTH_NOT_FOUND = -3, /*!< returned by register_verify */ - AUTH_FAKE_AUTH = -4, AUTH_UNKNOWN_DOMAIN = -5, AUTH_PEER_NOT_DYNAMIC = -6, AUTH_ACL_FAILED = -7, diff --git a/channels/sip/security_events.c b/channels/sip/security_events.c index 4045ae14d098f2c5fc2680298d163a5e89af6fdb..77dfa2e17c625f7b4cb3137f5ef7c859acf75e58 100644 --- a/channels/sip/security_events.c +++ b/channels/sip/security_events.c @@ -342,9 +342,6 @@ int sip_report_security_event(const struct sip_pvt *p, const struct sip_request /* with sip_cfg.alwaysauthreject on, generates 2 events */ sip_report_invalid_peer(p); break; - case AUTH_FAKE_AUTH: - sip_report_invalid_peer(p); - break; case AUTH_UNKNOWN_DOMAIN: snprintf(aclname, sizeof(aclname), "domain_must_match"); sip_report_failed_acl(p, aclname);