[svn-commits] rizzo: branch rizzo/astobj2 r45988 - /team/rizzo/astobj2/channels/chan_sip.c

svn-commits at lists.digium.com svn-commits at lists.digium.com
Mon Oct 23 09:44:13 MST 2006


Author: rizzo
Date: Mon Oct 23 11:44:12 2006
New Revision: 45988

URL: http://svn.digium.com/view/asterisk?rev=45988&view=rev
Log:
merge from trunk


Modified:
    team/rizzo/astobj2/channels/chan_sip.c

Modified: team/rizzo/astobj2/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/channels/chan_sip.c?rev=45988&r1=45987&r2=45988&view=diff
==============================================================================
--- team/rizzo/astobj2/channels/chan_sip.c (original)
+++ team/rizzo/astobj2/channels/chan_sip.c Mon Oct 23 11:44:12 2006
@@ -317,11 +317,14 @@
 
 /*! \brief Authentication result from check_auth* functions */
 enum check_auth_result {
+	AUTH_DONT_KNOW = -100,	/*!< no result, need to check further */
+		/* XXX maybe this is the same as AUTH_NOT_FOUND */
+
 	AUTH_SUCCESSFUL = 0,
 	AUTH_CHALLENGE_SENT = 1,
 	AUTH_SECRET_FAILED = -1,
 	AUTH_USERNAME_MISMATCH = -2,
-	AUTH_NOT_FOUND = -3,
+	AUTH_NOT_FOUND = -3,	/* returned by register_verify */
 	AUTH_FAKE_AUTH = -4,
 	AUTH_UNKNOWN_DOMAIN = -5,
 };
@@ -516,6 +519,7 @@
 static int srvlookup;			/*!< SRV Lookup on or off. Default is off, RFC behavior is on */
 static int pedanticsipchecking;		/*!< Extra checking ?  Default off */
 static int autocreatepeer;		/*!< Auto creation of peers at registration? Default off. */
+static int match_auth_username;		/*!< Match auth username if available instead of From: Default off. */
 static int global_relaxdtmf;			/*!< Relax DTMF */
 static int global_rtptimeout;		/*!< Time out call if no RTP */
 static int global_rtpholdtimeout;
@@ -908,6 +912,7 @@
 		AST_STRING_FIELD(cid_name);	/*!< Caller*ID name */
 		AST_STRING_FIELD(via);		/*!< Via: header */
 		AST_STRING_FIELD(fullcontact);	/*!< The Contact: that the UA registers with us */
+			/* we only store the part in <brackets> in this field. */
 		AST_STRING_FIELD(our_contact);	/*!< Our contact header */
 		AST_STRING_FIELD(rpid);		/*!< Our RPID header */
 		AST_STRING_FIELD(rpid_from);	/*!< Our RPID From header */
@@ -2228,6 +2233,75 @@
 		}
 	}
 	return tmp;
+}
+
+/*!
+ * parses a URI in its components.
+ * If scheme is specified, drop it from the top.
+ * If a component is not requested, do not split around it.
+ * This means that if we don't have domain, we cannot split
+ * name:pass and domain:port.
+ * It is safe to call with ret_name, pass, domain, port
+ * pointing all to the same place.
+ * Init pointers to empty string so we never get NULL dereferencing.
+ * Overwrites the string.
+ * return 0 on success, other values on error.
+ */
+static int parse_uri(char *uri, char *scheme,
+	char **ret_name, char **pass, char **domain, char **port, char **options)
+{
+	char *name = NULL;
+	int error = 0;
+
+	/* init field as required */
+	if (*pass)
+		*pass = "";
+	if (*port)
+		*port = "";
+	name = strsep(&uri, ";");	/* remove options */
+	if (scheme) {
+		int l = strlen(scheme);
+		if (!strncmp(name, scheme, l))
+			name += l;
+		else {
+			ast_log(LOG_NOTICE, "Missing scheme '%s' in '%s'\n", scheme, name);
+			error = -1;
+		}
+	}
+	if (!domain) {
+		/* if we don't want to split around domain, keep everything as a name,
+		 * so we need to do nothing here, except remember why.
+		 */
+	} else {
+		/* store the result in a temp. variable to avoid it being
+		 * overwritten if arguments point to the same place.
+		 */
+		char *c, *dom = "";
+
+		if ((c = strchr(name, '@')) == NULL) {
+			/* domain-only URI, according to the SIP RFC. */
+			dom = name;
+			name = "";
+		} else {
+			*c++ = '\0';
+			dom = c;
+		}
+		if (port && (c = strchr(dom, ':'))) { /* Remove :port */
+			*c++ = '\0';
+			*port = c;
+		}
+		if (pass && (c = strchr(name, ':'))) {	/* user:password */
+			*c++ = '\0';
+			*pass = c;
+		}
+		*domain = dom;
+	}
+	if (ret_name)	/* same as for domain, store the result only at the end */
+		*ret_name = name;
+	if (options)
+		*options = uri ? uri : "";
+
+	return error;
 }
 
 /*! \brief Send SIP MESSAGE text within a call
@@ -7517,7 +7591,7 @@
 	struct hostent *hp;
 	struct ast_hostent ahp;
 	int port;
-	char *c, *host, *pt;
+	char *host, *pt;
 	char *contact;
 
 
@@ -7531,32 +7605,12 @@
 
 	/* Work on a copy */
 	contact = ast_strdupa(pvt->fullcontact);
-
-	/* XXX this code is repeated all over */
-	/* Make sure it's a SIP URL */
-	if (strncasecmp(contact, "sip:", 4)) {
+	/* We have only the part in <brackets> here so we just need to parse a SIP URI.*/
+
+	if (parse_uri(contact, "sip:", &contact, NULL, &host, &pt, NULL))
 		ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", contact);
-	} else
-		contact += 4;
-
-	/* Ditch arguments */
-	/* XXX this code is replicated also shortly below */
-	contact = strsep(&contact, ";");	/* trim ; and beyond */
-
-	/* Grab host */
-	host = strchr(contact, '@');
-	if (!host) {	/* No username part */
-		host = contact;
-		c = NULL;
-	} else {
-		*host++ = '\0';
-	}
-	pt = strchr(host, ':');
-	if (pt) {
-		*pt++ = '\0';
-		port = atoi(pt);
-	} else
-		port = STANDARD_SIP_PORT;
+	port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_SIP_PORT;
+	ast_verbose("--- set_address_from_contact host '%s'\n", host);
 
 	/* XXX This could block for a long time XXX */
 	/* We should only do this if it's a name, not an IP */
@@ -8072,6 +8126,24 @@
 	transmit_response_with_auth(p, "401 Unauthorized", req, p->randdata, reliable, "WWW-Authenticate", 0);
 }
 
+/*!
+ * Terminate the uri at the first ';' or space.
+ * Technically we should ignore escaped space per RFC3261 (19.1.1 etc)
+ * but don't do it for the time being. Remember the uri format is:
+ *
+ *	sip:user:password at host:port;uri-parameters?headers
+ *	sips:user:password at host:port;uri-parameters?headers
+ *
+ */
+static char *terminate_uri(char *uri)
+{
+	char *t = uri;
+	while (*t && *t > ' ' && *t != ';')
+		t++;
+	*t = '\0';
+	return uri;
+}
+
 /*! \brief Verify registration of user 
 	- Registration is done in several steps, first a REGISTER without auth
 	  to get a challenge (nonce) then a second one with auth
@@ -8084,15 +8156,10 @@
 	struct sip_peer *peer;
 	char tmp[256];
 	char *name, *c;
-	char *t;
 	char *domain;
 
-	/* Terminate URI */
-	t = uri;
-	while(*t && (*t > 32) && (*t != ';'))
-		t++;
-	*t = '\0';
-	
+	terminate_uri(uri);	/* warning, overwrite the string */
+
 	ast_copy_string(tmp, get_header(req, "To"), sizeof(tmp));
 	if (pedanticsipchecking)
 		ast_uri_decode(tmp);
@@ -8107,6 +8174,9 @@
 		ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_inet_ntoa(sin->sin_addr));
 	}
 
+	/* XXX here too we interpret a missing @domain as a name-only
+	 * URI, whereas the RFC says this is a domain-only uri.
+	 */
 	/* Strip off the domain name */
 	if ((c = strchr(name, '@'))) {
 		*c++ = '\0';
@@ -8679,13 +8749,13 @@
 		return -1;
 	}
 	c += 4;
+	if ((a = strchr(c, ';'))) 	/* Remove arguments */
+		*a = '\0';
+	
 	if ((a = strchr(c, '@'))) {	/* Separate Domain */
 		*a++ = '\0';
 		ast_copy_string(referdata->refer_to_domain, a, sizeof(referdata->refer_to_domain));
 	}
-	
-	if ((a = strchr(c, ';'))) 	/* Remove arguments */
-		*a = '\0';
 	
 	if (sip_debug_test_pvt(p))
 		ast_verbose("Looking for %s in %s\n", c, p->context);
@@ -8836,6 +8906,262 @@
 	return 0;
 }
 
+/*!
+ * duplicate a list of channel variables, \return the copy.
+ */
+static struct ast_variable *copy_vars(struct ast_variable *src)
+{
+	struct ast_variable *res = NULL, *tmp, *v = NULL;
+
+	for (v = src ; v ; v = v->next) {
+		if ((tmp = ast_variable_new(v->name, v->value))) {
+			tmp->next = res;
+			res = tmp;
+		}
+	}
+	return res;
+}
+
+static enum check_auth_result check_user_ok(struct sip_pvt *p, char *of,
+	struct sip_request *req, int sipmethod, struct sockaddr_in *sin,
+	enum xmittype reliable,
+	char *rpid_num, char *calleridname, char *uri2)
+{
+	enum check_auth_result res;
+	struct sip_user *user = find_user(of, 1);
+	int debug=sip_debug_test_addr(sin);
+
+	/* Find user based on user name in the from header */
+	if (!user) {
+		if (debug)
+			ast_verbose("No user '%s' in SIP users list\n", of);
+		return AUTH_DONT_KNOW;
+	}
+	if (!ast_apply_ha(user->ha, sin)) {
+		if (debug)
+			ast_verbose("Found user '%s' for '%s', but fails host access\n",
+				user->name, of);
+		ASTOBJ_UNREF(user,sip_destroy_user);
+		return AUTH_DONT_KNOW;
+	}
+	if (debug)
+		ast_verbose("Found user '%s' for '%s'\n", user->name, of);
+
+	ast_copy_flags(&p->flags[0], &user->flags[0], SIP_FLAGS_TO_COPY);
+	ast_copy_flags(&p->flags[1], &user->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	/* copy channel vars */
+	p->chanvars = copy_vars(user->chanvars);
+	p->prefs = user->prefs;
+	/* Set Frame packetization */
+	if (p->rtp) {
+		ast_rtp_codec_setpref(p->rtp, &p->prefs);
+		p->autoframing = user->autoframing;
+	}
+	/* replace callerid if rpid found, and not restricted */
+	if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
+		char *tmp;
+		if (*calleridname)
+			ast_string_field_set(p, cid_name, calleridname);
+		tmp = ast_strdupa(rpid_num);
+		if (ast_is_shrinkable_phonenumber(tmp))
+			ast_shrink_phone_number(tmp);
+		ast_string_field_set(p, cid_num, tmp);
+	}
+		
+	do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE) );
+
+	if (!(res = check_auth(p, req, user->name, user->secret, user->md5secret, sipmethod, uri2, reliable, ast_test_flag(req, SIP_PKT_IGNORE)))) {
+		sip_cancel_destroy(p);
+		ast_copy_flags(&p->flags[0], &user->flags[0], SIP_FLAGS_TO_COPY);
+		ast_copy_flags(&p->flags[1], &user->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+		/* Copy SIP extensions profile from INVITE */
+		if (p->sipoptions)
+			user->sipoptions = p->sipoptions;
+
+		/* If we have a call limit, set flag */
+		if (user->call_limit)
+			ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
+		if (!ast_strlen_zero(user->context))
+			ast_string_field_set(p, context, user->context);
+		if (!ast_strlen_zero(user->cid_num) && !ast_strlen_zero(p->cid_num)) {
+			char *tmp = ast_strdupa(user->cid_num);
+			if (ast_is_shrinkable_phonenumber(tmp))
+				ast_shrink_phone_number(tmp);
+			ast_string_field_set(p, cid_num, tmp);
+		}
+		if (!ast_strlen_zero(user->cid_name) && !ast_strlen_zero(p->cid_num))
+			ast_string_field_set(p, cid_name, user->cid_name);
+		ast_string_field_set(p, username, user->name);
+		ast_string_field_set(p, peername, user->name);
+		ast_string_field_set(p, peersecret, user->secret);
+		ast_string_field_set(p, peermd5secret, user->md5secret);
+		ast_string_field_set(p, subscribecontext, user->subscribecontext);
+		ast_string_field_set(p, accountcode, user->accountcode);
+		ast_string_field_set(p, language, user->language);
+		ast_string_field_set(p, mohsuggest, user->mohsuggest);
+		ast_string_field_set(p, mohinterpret, user->mohinterpret);
+		p->allowtransfer = user->allowtransfer;
+		p->amaflags = user->amaflags;
+		p->callgroup = user->callgroup;
+		p->pickupgroup = user->pickupgroup;
+		if (user->callingpres)	/* User callingpres setting will override RPID header */
+			p->callingpres = user->callingpres;
+		
+		/* Set default codec settings for this call */
+		p->capability = user->capability;		/* User codec choice */
+		p->jointcapability = user->capability;		/* Our codecs */
+		if (p->peercapability)				/* AND with peer's codecs */
+			p->jointcapability &= p->peercapability;
+		if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
+		    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
+			p->noncodeccapability |= AST_RTP_DTMF;
+		else
+			p->noncodeccapability &= ~AST_RTP_DTMF;
+		if (p->t38.peercapability)
+			p->t38.jointcapability &= p->t38.peercapability;
+		p->maxcallbitrate = user->maxcallbitrate;
+		/* If we do not support video, remove video from call structure */
+		if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
+			ast_rtp_destroy(p->vrtp);
+			p->vrtp = NULL;
+		}
+	}
+	ASTOBJ_UNREF(user, sip_destroy_user);
+	return res;
+}
+
+static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
+	struct sip_request *req, int sipmethod, struct sockaddr_in *sin,
+	struct sip_peer **authpeer,
+	enum xmittype reliable,
+	char *rpid_num, char *calleridname, char *uri2)
+{
+	enum check_auth_result res;
+	int debug=sip_debug_test_addr(sin);
+	struct sip_peer *peer;
+
+	if (sipmethod == SIP_SUBSCRIBE)
+		/* For subscribes, match on peer name only */
+		peer = find_peer(of, NULL, 1);
+	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);
+
+	if (!peer) {
+		if (debug)
+			ast_verbose("No matching peer for '%s' from '%s:%d'\n",
+				of, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
+		return AUTH_DONT_KNOW;
+	}
+
+	if (debug)
+		ast_verbose("Found peer '%s' for '%s' from %s:%d\n",
+			peer->name, of, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
+
+	/* XXX what about p->prefs = peer->prefs; ? */
+	/* Set Frame packetization */
+	if (p->rtp) {
+		ast_rtp_codec_setpref(p->rtp, &peer->prefs);
+		p->autoframing = peer->autoframing;
+	}
+
+	/* Take the peer */
+	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
+	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+
+	/* Copy SIP extensions profile to peer */
+	if (p->sipoptions)
+		peer->sipoptions = p->sipoptions;
+
+	/* replace callerid if rpid found, and not restricted */
+	if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
+		char *tmp = ast_strdupa(rpid_num);
+		if (*calleridname)
+			ast_string_field_set(p, cid_name, calleridname);
+		if (ast_is_shrinkable_phonenumber(tmp))
+			ast_shrink_phone_number(tmp);
+		ast_string_field_set(p, cid_num, tmp);
+	}
+	do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE));
+
+	ast_string_field_set(p, peersecret, peer->secret);
+	ast_string_field_set(p, peermd5secret, peer->md5secret);
+	ast_string_field_set(p, subscribecontext, peer->subscribecontext);
+	ast_string_field_set(p, mohinterpret, peer->mohinterpret);
+	ast_string_field_set(p, mohsuggest, peer->mohsuggest);
+	if (peer->callingpres)	/* Peer calling pres setting will override RPID */
+		p->callingpres = peer->callingpres;
+	if (peer->maxms && peer->lastms)
+		p->timer_t1 = peer->lastms;
+	if (ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)) {
+		/* Pretend there is no required authentication */
+		ast_string_field_free(p, peersecret);
+		ast_string_field_free(p, peermd5secret);
+	}
+	if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable, ast_test_flag(req, SIP_PKT_IGNORE)))) {
+		ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
+		ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+		/* If we have a call limit, set flag */
+		if (peer->call_limit)
+			ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
+		ast_string_field_set(p, peername, peer->name);
+		ast_string_field_set(p, authname, peer->name);
+
+		/* copy channel vars */
+		p->chanvars = copy_vars(peer->chanvars);
+		if (authpeer) {
+			(*authpeer) = ASTOBJ_REF(peer);	/* Add a ref to the object here, to keep it in memory a bit longer if it is realtime */
+		}
+
+		if (!ast_strlen_zero(peer->username)) {
+			ast_string_field_set(p, username, peer->username);
+			/* Use the default username for authentication on outbound calls */
+			/* XXX this takes the name from the caller... can we override ? */
+			ast_string_field_set(p, authname, peer->username);
+		}
+		if (!ast_strlen_zero(peer->cid_num) && !ast_strlen_zero(p->cid_num)) {
+			char *tmp = ast_strdupa(peer->cid_num);
+			if (ast_is_shrinkable_phonenumber(tmp))
+				ast_shrink_phone_number(tmp);
+			ast_string_field_set(p, cid_num, tmp);
+		}
+		if (!ast_strlen_zero(peer->cid_name) && !ast_strlen_zero(p->cid_name)) 
+			ast_string_field_set(p, cid_name, peer->cid_name);
+		ast_string_field_set(p, fullcontact, peer->fullcontact);
+		if (!ast_strlen_zero(peer->context))
+			ast_string_field_set(p, context, peer->context);
+		ast_string_field_set(p, peersecret, peer->secret);
+		ast_string_field_set(p, peermd5secret, peer->md5secret);
+		ast_string_field_set(p, language, peer->language);
+		ast_string_field_set(p, accountcode, peer->accountcode);
+		p->amaflags = peer->amaflags;
+		p->callgroup = peer->callgroup;
+		p->pickupgroup = peer->pickupgroup;
+		p->capability = peer->capability;
+		p->prefs = peer->prefs;
+		p->jointcapability = peer->capability;
+		if (p->peercapability)
+			p->jointcapability &= p->peercapability;
+		p->maxcallbitrate = peer->maxcallbitrate;
+		if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
+			ast_rtp_destroy(p->vrtp);
+			p->vrtp = NULL;
+		}
+		if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
+		    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
+			p->noncodeccapability |= AST_RTP_DTMF;
+		else
+			p->noncodeccapability &= ~AST_RTP_DTMF;
+		if (p->t38.peercapability)
+			p->t38.jointcapability &= p->t38.peercapability;
+	}
+	ASTOBJ_UNREF(peer, sip_destroy_peer);
+	return res;
+}
+
 
 /*! \brief  Check if matching user or peer is defined 
  	Match user on From: user name and peer on IP/port
@@ -8846,25 +9172,19 @@
 					      int sipmethod, char *uri, enum xmittype reliable,
 					      struct sockaddr_in *sin, struct sip_peer **authpeer)
 {
-	struct sip_user *user = NULL;
-	struct sip_peer *peer;
-	char from[256], *c;
+	char from[256];
+	char *dummy;	/* dummy return value for parse_uri */
+	char *domain;	/* dummy return value for parse_uri */
 	char *of;
 	char rpid_num[50];
 	const char *rpid;
-	enum check_auth_result res = AUTH_SUCCESSFUL;
-	char *t;
+	enum check_auth_result res;
 	char calleridname[50];
-	int debug=sip_debug_test_addr(sin);
-	struct ast_variable *tmpvar = NULL, *v = NULL;
 	char *uri2 = ast_strdupa(uri);
 
-	/* Terminate URI */
-	t = uri2;
-	while (*t && *t > 32 && *t != ';')
-		t++;
-	*t = '\0';
-	ast_copy_string(from, get_header(req, "From"), sizeof(from));	/* XXX bug in original code, overwrote string */
+	terminate_uri(uri2);	/* trim extra stuff */
+
+	ast_copy_string(from, get_header(req, "From"), sizeof(from));
 	if (pedanticsipchecking)
 		ast_uri_decode(from);
 	/* XXX here tries to map the username for invite things */
@@ -8880,7 +9200,7 @@
 
 	of = get_in_brackets(from);
 	if (ast_strlen_zero(p->exten)) {
-		t = uri2;
+		char *t = uri2;
 		if (!strncmp(t, "sip:", 4))
 			t+= 4;
 		ast_string_field_set(p, exten, t);
@@ -8892,17 +9212,22 @@
 	}
 	/* save the URI part of the From header */
 	ast_string_field_set(p, from, of);
-	if (strncmp(of, "sip:", 4)) {
+
+	/* ignore all fields but name */
+	if (parse_uri(of, "sip:", &of, &dummy, &domain, &dummy, &dummy)) {
 		ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
-	} else
-		of += 4;
-	/* Get just the username part */
-	if ((c = strchr(of, '@'))) {
-		char *tmp;
-		*c = '\0';
-		if ((c = strchr(of, ':')))
-			*c = '\0';
-		tmp = ast_strdupa(of);
+	}
+	if (ast_strlen_zero(of)) {
+		/* XXX note: the original code considered a missing @host
+		 * as a username-only URI. The SIP RFC (19.1.1) says that
+		 * this is wrong, and it should be considered as a domain-only URI.
+		 * For backward compatibility, we keep this block, but it is
+		 * really a mistake and should go away.
+		 */
+		of = domain;
+	}
+	{
+		char *tmp = ast_strdupa(of);
 		if (ast_is_shrinkable_phonenumber(tmp))
 			ast_shrink_phone_number(tmp);
 		ast_string_field_set(p, cid_num, tmp);
@@ -8910,256 +9235,48 @@
 	if (ast_strlen_zero(of))
 		return AUTH_SUCCESSFUL;
 
-	if (1) {
+	if (match_auth_username) {
 		/*
 		 * XXX This is experimental code to grab the search key from the
 		 * Auth header's username instead of the 'From' name, if available.
 		 * Do not enable this block unless you understand the side effects (if any!)
 		 * Note, the search for "username" should be done in a more robust way.
+		 * Note2, at the moment we chech both fields, though maybe we should
+		 * pick one or another depending on the request ? XXX
 		 */
-		const char *hdr = (sipmethod == SIP_REGISTER || sipmethod == SIP_SUBSCRIBE) ?
-			"Authorization" : "Proxy-Authorization";
-		if ( (hdr = get_header(req, hdr)) && (hdr = strstr(hdr, "username=\"")) ) {
+		const char *hdr = get_header(req, "Authorization");
+		if (ast_strlen_zero(hdr))
+			hdr = get_header(req, "Proxy-Authorization");
+
+		if ( !ast_strlen_zero(hdr) && (hdr = strstr(hdr, "username=\"")) ) {
 			ast_copy_string(from, hdr + strlen("username=\""), sizeof(from));
 			of = from;
 			of = strsep(&of, "\"");
 		}
 	}
 
-	if (!authpeer)	/* If we are looking for a peer, don't check the user objects (or realtime) */
-		user = find_user(of, 1);
-
-	/* Find user based on user name in the from header */
-	if (user && ast_apply_ha(user->ha, sin)) {
-		ast_copy_flags(&p->flags[0], &user->flags[0], SIP_FLAGS_TO_COPY);
-		ast_copy_flags(&p->flags[1], &user->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
-		/* copy channel vars */
-		for (v = user->chanvars ; v ; v = v->next) {
-			if ((tmpvar = ast_variable_new(v->name, v->value))) {
-				tmpvar->next = p->chanvars; 
-				p->chanvars = tmpvar;
-			}
-		}
-		p->prefs = user->prefs;
-		/* Set Frame packetization */
-		if (p->rtp) {
-			ast_rtp_codec_setpref(p->rtp, &p->prefs);
-			p->autoframing = user->autoframing;
-		}
-		/* replace callerid if rpid found, and not restricted */
-		if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
-			char *tmp;
-			if (*calleridname)
-				ast_string_field_set(p, cid_name, calleridname);
-			tmp = ast_strdupa(rpid_num);
-			if (ast_is_shrinkable_phonenumber(tmp))
-				ast_shrink_phone_number(tmp);
-			ast_string_field_set(p, cid_num, tmp);
-		}
-		
-		do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE) );
-
-		if (!(res = check_auth(p, req, user->name, user->secret, user->md5secret, sipmethod, uri2, reliable, ast_test_flag(req, SIP_PKT_IGNORE)))) {
-			sip_cancel_destroy(p);
-			ast_copy_flags(&p->flags[0], &user->flags[0], SIP_FLAGS_TO_COPY);
-			ast_copy_flags(&p->flags[1], &user->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
-			/* Copy SIP extensions profile from INVITE */
-			if (p->sipoptions)
-				user->sipoptions = p->sipoptions;
-
-			/* If we have a call limit, set flag */
-			if (user->call_limit)
-				ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
-			if (!ast_strlen_zero(user->context))
-				ast_string_field_set(p, context, user->context);
-			if (!ast_strlen_zero(user->cid_num) && !ast_strlen_zero(p->cid_num)) {
-				char *tmp = ast_strdupa(user->cid_num);
-				if (ast_is_shrinkable_phonenumber(tmp))
-					ast_shrink_phone_number(tmp);
-				ast_string_field_set(p, cid_num, tmp);
-			}
-			if (!ast_strlen_zero(user->cid_name) && !ast_strlen_zero(p->cid_num))
-				ast_string_field_set(p, cid_name, user->cid_name);
-			ast_string_field_set(p, username, user->name);
-			ast_string_field_set(p, peername, user->name);
-			ast_string_field_set(p, peersecret, user->secret);
-			ast_string_field_set(p, peermd5secret, user->md5secret);
-			ast_string_field_set(p, subscribecontext, user->subscribecontext);
-			ast_string_field_set(p, accountcode, user->accountcode);
-			ast_string_field_set(p, language, user->language);
-			ast_string_field_set(p, mohsuggest, user->mohsuggest);
-			ast_string_field_set(p, mohinterpret, user->mohinterpret);
-			p->allowtransfer = user->allowtransfer;
-			p->amaflags = user->amaflags;
-			p->callgroup = user->callgroup;
-			p->pickupgroup = user->pickupgroup;
-			if (user->callingpres)	/* User callingpres setting will override RPID header */
-				p->callingpres = user->callingpres;
-			
-			/* Set default codec settings for this call */
-			p->capability = user->capability;		/* User codec choice */
-			p->jointcapability = user->capability;		/* Our codecs */
-			if (p->peercapability)				/* AND with peer's codecs */
-				p->jointcapability &= p->peercapability;
-			if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
-			    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
-				p->noncodeccapability |= AST_RTP_DTMF;
-			else
-				p->noncodeccapability &= ~AST_RTP_DTMF;
-			if (p->t38.peercapability)
-				p->t38.jointcapability &= p->t38.peercapability;
-			p->maxcallbitrate = user->maxcallbitrate;
-			/* If we do not support video, remove video from call structure */
-			if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
-				ast_rtp_destroy(p->vrtp);
-				p->vrtp = NULL;
-			}
-		}
-		if (user && debug)
-			ast_verbose("Found user '%s'\n", user->name);
-	} else {
-		if (user) {
-			if (!authpeer && debug)
-				ast_verbose("Found user '%s', but fails host access\n", user->name);
-			ASTOBJ_UNREF(user,sip_destroy_user);
-		}
-		user = NULL;
-	}
-
-	if (!user) {
-		/* If we didn't find a user match, check for peers */
-		if (sipmethod == SIP_SUBSCRIBE)
-			/* For subscribes, match on peer name only */
-			peer = find_peer(of, NULL, 1);
-		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);
-
-		if (peer) {
-			/* Set Frame packetization */
-			if (p->rtp) {
-				ast_rtp_codec_setpref(p->rtp, &peer->prefs);
-				p->autoframing = peer->autoframing;
-			}
-			if (debug)
-				ast_verbose("Found peer '%s'\n", peer->name);
-
-			/* Take the peer */
-			ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
-			ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
-
-			/* Copy SIP extensions profile to peer */
-			if (p->sipoptions)
-				peer->sipoptions = p->sipoptions;
-
-			/* replace callerid if rpid found, and not restricted */
-			if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
-				char *tmp = ast_strdupa(rpid_num);
-				if (*calleridname)
-					ast_string_field_set(p, cid_name, calleridname);
-				if (ast_is_shrinkable_phonenumber(tmp))
-					ast_shrink_phone_number(tmp);
-				ast_string_field_set(p, cid_num, tmp);
-			}
-			do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE));
-
-			ast_string_field_set(p, peersecret, peer->secret);
-			ast_string_field_set(p, peermd5secret, peer->md5secret);
-			ast_string_field_set(p, subscribecontext, peer->subscribecontext);
-			ast_string_field_set(p, mohinterpret, peer->mohinterpret);
-			ast_string_field_set(p, mohsuggest, peer->mohsuggest);
-			if (peer->callingpres)	/* Peer calling pres setting will override RPID */
-				p->callingpres = peer->callingpres;
-			if (peer->maxms && peer->lastms)
-				p->timer_t1 = peer->lastms;
-			if (ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)) {
-				/* Pretend there is no required authentication */
-				ast_string_field_free(p, peersecret);
-				ast_string_field_free(p, peermd5secret);
-			}
-			if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable, ast_test_flag(req, SIP_PKT_IGNORE)))) {
-				ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
-				ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
-				/* If we have a call limit, set flag */
-				if (peer->call_limit)
-					ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
-				ast_string_field_set(p, peername, peer->name);
-				ast_string_field_set(p, authname, peer->name);
-
-				/* copy channel vars */
-				for (v = peer->chanvars ; v ; v = v->next) {
-					if ((tmpvar = ast_variable_new(v->name, v->value))) {
-						tmpvar->next = p->chanvars; 
-						p->chanvars = tmpvar;
-					}
-				}
-				if (authpeer) {
-					(*authpeer) = ASTOBJ_REF(peer);	/* Add a ref to the object here, to keep it in memory a bit longer if it is realtime */
-				}
-
-				if (!ast_strlen_zero(peer->username)) {
-					ast_string_field_set(p, username, peer->username);
-					/* Use the default username for authentication on outbound calls */
-					/* XXX this takes the name from the caller... can we override ? */
-					ast_string_field_set(p, authname, peer->username);
-				}
-				if (!ast_strlen_zero(peer->cid_num) && !ast_strlen_zero(p->cid_num)) {
-					char *tmp = ast_strdupa(peer->cid_num);
-					if (ast_is_shrinkable_phonenumber(tmp))
-						ast_shrink_phone_number(tmp);
-					ast_string_field_set(p, cid_num, tmp);
-				}
-				if (!ast_strlen_zero(peer->cid_name) && !ast_strlen_zero(p->cid_name)) 
-					ast_string_field_set(p, cid_name, peer->cid_name);
-				ast_string_field_set(p, fullcontact, peer->fullcontact);
-				if (!ast_strlen_zero(peer->context))
-					ast_string_field_set(p, context, peer->context);
-				ast_string_field_set(p, peersecret, peer->secret);
-				ast_string_field_set(p, peermd5secret, peer->md5secret);
-				ast_string_field_set(p, language, peer->language);
-				ast_string_field_set(p, accountcode, peer->accountcode);
-				p->amaflags = peer->amaflags;
-				p->callgroup = peer->callgroup;
-				p->pickupgroup = peer->pickupgroup;
-				p->capability = peer->capability;
-				p->prefs = peer->prefs;
-				p->jointcapability = peer->capability;
-				if (p->peercapability)
-					p->jointcapability &= p->peercapability;
-				p->maxcallbitrate = peer->maxcallbitrate;
-				if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
-					ast_rtp_destroy(p->vrtp);
-					p->vrtp = NULL;
-				}
-				if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
-				    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
-					p->noncodeccapability |= AST_RTP_DTMF;
-				else
-					p->noncodeccapability &= ~AST_RTP_DTMF;
-				if (p->t38.peercapability)
-					p->t38.jointcapability &= p->t38.peercapability;
-			}
-			ASTOBJ_UNREF(peer, sip_destroy_peer);
-		} else { 
-			if (debug)
-				ast_verbose("Found no matching peer or user for '%s:%d'\n", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
-
-			/* 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 */
-			}
-		}
-
-	}
-
-	if (user)
-		ASTOBJ_UNREF(user, sip_destroy_user);
+	if (!authpeer) {
+		/* If we are looking for a peer, don't check the
+		   user objects (or realtime) */
+		res = check_user_ok(p, of, req, sipmethod, sin,
+			reliable, rpid_num, calleridname, uri2);
+		if (res != AUTH_DONT_KNOW)
+			return res;
+	}
+
+	res = check_peer_ok(p, of, req, sipmethod, sin,
+			authpeer, reliable, rpid_num, calleridname, uri2);
+	if (res != AUTH_DONT_KNOW)
+		return res;
+
+	/* Finally, apply the guest policy */
+	if (global_allowguest)
+		res = AUTH_SUCCESSFUL;
+	else 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 */
+
 	return res;
 }
 
@@ -10176,6 +10293,7 @@
 	ast_cli(fd, "  Bindaddress:            %s\n", ast_inet_ntoa(bindaddr.sin_addr));
 	ast_cli(fd, "  Videosupport:           %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "Yes" : "No");
 	ast_cli(fd, "  AutoCreatePeer:         %s\n", autocreatepeer ? "Yes" : "No");
+	ast_cli(fd, "  MatchAuthUsername:      %s\n", match_auth_username ? "Yes" : "No");
 	ast_cli(fd, "  Allow unknown access:   %s\n", global_allowguest ? "Yes" : "No");
 	ast_cli(fd, "  Allow subscriptions:    %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWSUBSCRIBE) ? "Yes" : "No");
 	ast_cli(fd, "  Allow overlap dialing:  %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP) ? "Yes" : "No");
@@ -15343,14 +15461,30 @@
 	return a;
 }
 
+/*!
+ * implement the servar config line
+ */
+static struct ast_variable *add_var(const char *buf, struct ast_variable *list)
+{
+	struct ast_variable *tmpvar = NULL;
+	char *varname = ast_strdupa(buf), *varval = NULL;
+	
+	if ((varval = strchr(varname,'='))) {
+		*varval++ = '\0';
+		if ((tmpvar = ast_variable_new(varname, varval))) {
+			tmpvar->next = list;
+			list = tmpvar;
+		}
+	}
+	return list;
+}
+
 /*! \brief Initiate a SIP user structure from configuration (configuration or realtime) */
 static struct sip_user *build_user(const char *name, struct ast_variable *v, int realtime)
 {
 	struct sip_user *user;
 	int format;
 	struct ast_ha *oldha = NULL;
-	char *varname = NULL, *varval = NULL;
-	struct ast_variable *tmpvar = NULL;
 	struct ast_flags userflags[2] = {{(0)}};
 	struct ast_flags mask[2] = {{(0)}};
 
@@ -15383,14 +15517,7 @@
 		} else if (!strcasecmp(v->name, "subscribecontext")) {
 			ast_copy_string(user->subscribecontext, v->value, sizeof(user->subscribecontext));
 		} else if (!strcasecmp(v->name, "setvar")) {
-			varname = ast_strdupa(v->value);
-			if ((varval = strchr(varname,'='))) {
-				*varval++ = '\0';
-				if ((tmpvar = ast_variable_new(varname, varval))) {
-					tmpvar->next = user->chanvars;
-					user->chanvars = tmpvar;
-				}
-			}
+			user->chanvars = add_var(v->value, user->chanvars);
 		} else if (!strcasecmp(v->name, "permit") ||
 				   !strcasecmp(v->name, "deny")) {
 			user->ha = ast_append_ha(v->name, v->value, user->ha);
@@ -15533,8 +15660,6 @@
 	int firstpass=1;
 	int format=0;		/* Ama flags */
 	time_t regseconds = 0;
-	char *varname = NULL, *varval = NULL;
-	struct ast_variable *tmpvar = NULL;
 	struct ast_flags peerflags[2] = {{(0)}};
 	struct ast_flags mask[2] = {{(0)}};
 	char contact[256] = "";
@@ -15727,15 +15852,7 @@
 				peer->rtpkeepalive = global_rtpkeepalive;
 			}
 		} else if (!strcasecmp(v->name, "setvar")) {
-			/* Set peer channel variable */
-			varname = ast_strdupa(v->value);
-			if ((varval = strchr(varname, '='))) {
-				*varval++ = '\0';
-				if ((tmpvar = ast_variable_new(varname, varval))) {
-					tmpvar->next = peer->chanvars;
-					peer->chanvars = tmpvar;
-				}
-			}
+			peer->chanvars = add_var(v->value, peer->chanvars);
 		} else if (!strcasecmp(v->name, "qualify")) {
 			if (!strcasecmp(v->value, "no")) {
 				peer->maxms = 0;
@@ -16007,6 +16124,8 @@
 			outboundproxyip.sin_port = htons(format);
 		} else if (!strcasecmp(v->name, "autocreatepeer")) {
 			autocreatepeer = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "match_auth_username")) {
+			match_auth_username = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "srvlookup")) {
 			srvlookup = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "pedantic")) {



More information about the svn-commits mailing list