Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 382194)
+++ channels/chan_sip.c	(working copy)
@@ -369,7 +369,6 @@
 	AUTH_SECRET_FAILED = -1,
 	AUTH_USERNAME_MISMATCH = -2,
 	AUTH_NOT_FOUND = -3,
-	AUTH_FAKE_AUTH = -4,
 	AUTH_UNKNOWN_DOMAIN = -5,
 	AUTH_PEER_NOT_DYNAMIC = -6,
 	AUTH_ACL_FAILED = -7,
@@ -1386,6 +1385,11 @@
 	ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer);
 } peerl;
 
+/*! \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 proxys we register with and place calls to */
 static struct ast_register_list {
 	ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
@@ -1504,7 +1508,7 @@
 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, int inc, enum xmittype reliable, int newbranch);
 static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch);
 static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init);
@@ -11069,13 +11073,14 @@
 					 const char *secret, const char *md5secret, int sipmethod,
 					 char *uri, enum xmittype reliable, int ignore)
 {
-	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;
 	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->randdata;
@@ -11098,14 +11103,6 @@
 	/* Always OK if no secret */
 	if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret))
 		return AUTH_SUCCESSFUL;
-	if (sipmethod == SIP_REGISTER || sipmethod == SIP_SUBSCRIBE) {
-		/* On a REGISTER, we have to use 401 and its family of headers instead of 407 and its family
-		   of headers -- GO SIP!  Whoo hoo!  Two things that do the same thing but are used in
-		   different circumstances! What a surprise. */
-		response = "401 Unauthorized";
-		reqheader = "Authorization";
-		respheader = "WWW-Authenticate";
-	}
 	authtoken =  get_header(req, reqheader);	
 	if (ignore && !ast_strlen_zero(p->randdata) && ast_strlen_zero(authtoken)) {
 		/* This is a retransmitted invite/register/etc, don't reconstruct authentication
@@ -11163,8 +11160,14 @@
 			strsep(&c, " ,");
 	}
 
+	/* 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 */
@@ -11202,7 +11205,8 @@
 	}
 
 	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)
@@ -11462,13 +11466,13 @@
 /*! \brief Send a fake 401 Unauthorized response when the administrator
   wants to hide the names of local users/peers 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_dynamic_str *buf;
 	char *c;
@@ -11483,11 +11487,6 @@
 		[K_LAST] = { NULL, NULL}
 	};
 
-	if (sipmethod == SIP_REGISTER || sipmethod == SIP_SUBSCRIBE) {
-		response = "401 Unauthorized";
-		reqheader = "Authorization";
-		respheader = "WWW-Authenticate";
-	}
 	authtoken = get_header(req, reqheader);
 	if (ast_test_flag(req, SIP_PKT_IGNORE) && !ast_strlen_zero(p->randdata) && ast_strlen_zero(authtoken)) {
 		/* This is a retransmitted invite/register/etc, don't reconstruct authentication
@@ -11506,13 +11505,13 @@
 	}
 
 	if (!(buf = ast_dynamic_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_dynamic_str_thread_set(&buf, 0, &check_auth_buf, "%s", authtoken) == AST_DYNSTR_BUILD_FAILED) {
-		transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
+		__transmit_response(p, "403 Forbidden", &p->initreq, reliable);
 		return;
 	}
 
@@ -11550,7 +11549,7 @@
 		/* 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);
 	}
 }
 
@@ -11621,6 +11620,14 @@
 		}
 	}
 	peer = find_peer(name, NULL, 1, 0);
+
+	/* If we don't want username disclosure, use the bogus_peer when a user
+	 * is not found. */
+	if (!peer && global_alwaysauthreject && !autocreatepeer) {
+		peer = bogus_peer;
+		ASTOBJ_REF(peer);
+	}
+
 	if (!(peer && ast_apply_ha(peer->ha, sin))) {
 		/* Peer fails ACL check */
 		if (peer) {
@@ -11691,7 +11698,7 @@
 			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);
 				peer->lastmsgssent = -1;
 				res = 0;
 				break;
@@ -11734,7 +11741,7 @@
 		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);
 			break;
 		case AUTH_USERNAME_MISMATCH:
 			/* Username and digest username does not match.
@@ -11745,7 +11752,7 @@
 		case AUTH_PEER_NOT_DYNAMIC:
 		case AUTH_ACL_FAILED:
 			if (global_alwaysauthreject) {
-				transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE);
+				transmit_fake_auth_response(p, &p->initreq, XMIT_UNRELIABLE);
 			} else {
 				/* URI not found */
 				if (res == AUTH_PEER_NOT_DYNAMIC)
@@ -12782,24 +12789,39 @@
 
 	if (!user) {
 		/* If we didn't find a user match, check for peers */
-		if (sipmethod == SIP_SUBSCRIBE)
+		if (sipmethod == SIP_SUBSCRIBE) {
 			/* For subscribes, match on peer name only */
 			peer = find_peer(of, NULL, 1, 0);
-		else
+		} else {
 			/* Look for peer based on the IP address we received data from */
 			/* If peer is registered from this IP address or have this as a default
 			   IP address, this call is from the peer 
 			*/
 			peer = find_peer(NULL, &p->recv, 1, 0);
+		}
 
+		if (!peer) {
+			/* 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 (!global_allowguest && global_alwaysauthreject) {
+				/* 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;
+				ASTOBJ_REF(peer);
+			}
+		}
+
 		if (peer) {
 			/* Set Frame packetization */
 			if (p->rtp) {
 				ast_rtp_codec_setpref(p->rtp, &peer->prefs);
 				p->autoframing = peer->autoframing;
 			}
-			if (debug)
+			if (debug && peer != bogus_peer) {
 				ast_verbose("Found peer '%s'\n", peer->name);
+			}
 
 			/* Take the peer */
 			ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
@@ -12924,10 +12946,7 @@
 
 			/* do we allow guests? */
 			if (!global_allowguest) {
-				if (global_alwaysauthreject)
-					res = AUTH_FAKE_AUTH; /* reject with fake authorization request */
-				else
-					res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */
+				res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */
 			} else {
 				get_rpid(p, req);
 				res = AUTH_SUCCESSFUL;
@@ -17352,13 +17371,8 @@
 			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", 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", get_header(req, "From"));
-				transmit_response(p, "403 Forbidden", req);
-			}
+			ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+			transmit_response(p, "403 Forbidden", req);
 			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 			return 0;
 		}
@@ -18209,13 +18223,8 @@
 			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 user %s\n", get_header(req, "From"));
-				transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE);
-			} else {
-  				ast_log(LOG_NOTICE, "Failed to authenticate user %s\n", get_header(req, "From"));
-				transmit_response_reliable(p, "403 Forbidden", req);
-  			}
+			ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+			transmit_response_reliable(p, "403 Forbidden", req);
 			p->invitestate = INV_COMPLETED;	
 			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 			ast_string_field_free(p, theirtag);
@@ -19411,7 +19420,7 @@
 	 * use if !(ast_test_flag(req, SIP_PKT_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, sin, &authpeer);
+		res = check_user_full(p, req, SIP_SUBSCRIBE, e, XMIT_UNRELIABLE, sin, &authpeer);
 
 		/* if an authentication response was sent, we are done here */
 		if (res == AUTH_CHALLENGE_SENT) {
@@ -19420,13 +19429,8 @@
 			return 0;
 		}
 		if (res < 0) {
-			if (res == AUTH_FAKE_AUTH) {
-				ast_log(LOG_NOTICE, "Sending fake auth rejection for user %s\n", get_header(req, "From"));
-				transmit_fake_auth_response(p, SIP_SUBSCRIBE, req, XMIT_UNRELIABLE);
-			} else {
-				ast_log(LOG_NOTICE, "Failed to authenticate user %s for SUBSCRIBE\n", get_header(req, "From"));
-				transmit_response_reliable(p, "403 Forbidden", req);
-			}
+			ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+			transmit_response(p, "403 Forbidden", req);
 			ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);	
 			if (authpeer)
 				ASTOBJ_UNREF(authpeer, sip_destroy_peer);
@@ -22917,6 +22921,7 @@
 /*! \brief Force reload of module from cli */
 static int sip_reload(int fd, int argc, char *argv[])
 {
+	static struct sip_peer *tmp_peer, *new_peer;
 	ast_mutex_lock(&sip_reload_lock);
 	if (sip_reloading) 
 		ast_verbose("Previous SIP reload not yet done\n");
@@ -22930,6 +22935,18 @@
 	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_copy_string(new_peer->md5secret, BOGUS_PEER_MD5SECRET, sizeof(new_peer->md5secret));
+		ast_clear_flag(&new_peer->flags[0], SIP_INSECURE_PORT | SIP_INSECURE_INVITE);
+		bogus_peer = new_peer;
+		ASTOBJ_UNREF(tmp_peer, sip_destroy_peer);
+	} else {
+		ast_log(LOG_ERROR, "Could not update the fake authentication peer.\n");
+		/* You probably have bigger (memory?) issues to worry about though.. */
+	}
+
 	return 0;
 }
 
@@ -23075,9 +23092,21 @@
 	if(reload_config(sip_reloadreason))	/* Load the configuration from sip.conf */
 		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);
+		sched_context_destroy(sched);
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	/* Make sure the auth will always fail. */
+	ast_copy_string(bogus_peer->md5secret, BOGUS_PEER_MD5SECRET, sizeof(bogus_peer->md5secret));
+	ast_clear_flag(&bogus_peer->flags[0], SIP_INSECURE_PORT | SIP_INSECURE_INVITE);
+
 	/* 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");
+		ASTOBJ_UNREF(bogus_peer, sip_destroy_peer);
 		io_context_destroy(io);
 		sched_context_destroy(sched);
 		return AST_MODULE_LOAD_FAILURE;
@@ -23190,6 +23219,8 @@
 	/* Free memory for local network address mask */
 	ast_free_ha(localaddr);
 
+	ASTOBJ_UNREF(bogus_peer, sip_destroy_peer);
+
 	ASTOBJ_CONTAINER_DESTROYALL(&userl, sip_destroy_user);
 	ASTOBJ_CONTAINER_DESTROY(&userl);
 	ASTOBJ_CONTAINER_DESTROYALL(&peerl, sip_destroy_peer);
