[Asterisk-cvs] asterisk/channels chan_sip.c,1.691,1.692

markster at lists.digium.com markster at lists.digium.com
Thu Mar 24 17:12:02 CST 2005


Update of /usr/cvsroot/asterisk/channels
In directory mongoose.digium.com:/tmp/cvs-serv32234/channels

Modified Files:
	chan_sip.c 
Log Message:
Add SIP real authentication (bug #3782)


Index: chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.691
retrieving revision 1.692
diff -u -d -r1.691 -r1.692
--- chan_sip.c	24 Mar 2005 05:02:49 -0000	1.691
+++ chan_sip.c	24 Mar 2005 23:06:21 -0000	1.692
@@ -291,11 +291,21 @@
 	char hop[0];
 };
 
+/* sip_history: Structure for saving transactions within a SIP dialog */
 struct sip_history {
 	char event[80];
 	struct sip_history *next;
 };
 
+/* sip_auth: Creadentials for authentication to other SIP services */
+struct sip_auth {
+	char realm[AST_MAX_EXTENSION];  /* Realm in which these credentials are valid */
+	char username[256];             /* Username */
+	char secret[256];               /* Secret */
+	char md5secret[256];            /* MD5Secret */
+	struct sip_auth *next;          /* Next auth structure in list */
+};
+
 #define SIP_ALREADYGONE		(1 << 0)	/* Whether or not we've already been destroyed by our peer */
 #define SIP_NEEDDESTROY		(1 << 1)	/* if we need to be destroyed */
 #define SIP_NOVIDEO		(1 << 2)	/* Didn't get video in invite, don't offer */
@@ -410,6 +420,7 @@
 	char okcontacturi[256];			/* URI from the 200 OK on INVITE */
 	char peersecret[256];			/* Password */
 	char peermd5secret[256];
+	struct sip_auth *peerauth;		/* Realm authentication */
 	char cid_num[256];			/* Caller*ID */
 	char cid_name[256];			/* Caller*ID */
 	char via[256];				/* Via: header */
@@ -505,6 +516,7 @@
 					/* peer->name is the unique name of this object */
 	char secret[80];		/* Password */
 	char md5secret[80];		/* Password in MD5 */
+	struct sip_auth *auth;		/* Realm authentication list */
 	char context[80];		/* Default context for incoming calls */
 	char username[80];		/* Temporary username until registration */ 
 	char accountcode[20];		/* Account code */
@@ -630,6 +642,9 @@
 /* The list of manual NOTIFY types we know how to send */
 struct ast_config *notify_types;
 
+static struct sip_auth *authl;          /* Authentication list */
+
+
 static struct ast_frame  *sip_read(struct ast_channel *ast);
 static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req);
 static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
@@ -667,6 +682,9 @@
 static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int sip_senddigit(struct ast_channel *ast, char digit);
 static int sip_sendtext(struct ast_channel *ast, char *text);
+static int clear_realm_authentication(struct sip_auth *authlist);                            /* Clear realm authentication list (at reload) */
+static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno);   /* Add realm authentication in list */
+static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, char *realm);         /* Find authentication for a specific realm */
 
 /* Definition of this channel for channel registration */
 static const struct ast_channel_tech sip_tech = {
@@ -716,6 +734,7 @@
 	return 1;
 }
 
+/*--- sip_debug_test_pvt: Test PVT for debugging output */
 static inline int sip_debug_test_pvt(struct sip_pvt *p) 
 {
 	if (sipdebug == 0)
@@ -1234,6 +1253,8 @@
 		rpeerobjs--;
 	else
 		speerobjs--;
+	clear_realm_authentication(peer->auth);
+	peer->auth = (struct sip_auth *) NULL;
 	free(peer);
 }
 
@@ -6513,6 +6534,7 @@
 	char codec_buf[512];
 	struct ast_codec_pref *pref;
 	struct ast_variable *v;
+	struct sip_auth *auth;
 	int x = 0, codec = 0, load_realtime = 0;
 
 	if (argc < 4)
@@ -6536,6 +6558,12 @@
 		ast_cli(fd, "  * Name       : %s\n", peer->name);
 		ast_cli(fd, "  Secret       : %s\n", ast_strlen_zero(peer->secret)?"<Not set>":"<Set>");
 		ast_cli(fd, "  MD5Secret    : %s\n", ast_strlen_zero(peer->md5secret)?"<Not set>":"<Set>");
+		auth = peer->auth;
+		while(auth) {
+			ast_cli(fd, "  Realm-auth   : Realm %-15.15s User %-10.20s ", auth->realm, auth->username);
+			ast_cli(fd, "%s\n", !ast_strlen_zero(auth->secret)?"<Secret set>":(!ast_strlen_zero(auth->md5secret)?"<MD5secret set>" : "<Not set>"));
+			auth = auth->next;
+		}
 		ast_cli(fd, "  Context      : %s\n", peer->context);
 		ast_cli(fd, "  Language     : %s\n", peer->language);
 		if (!ast_strlen_zero(peer->accountcode))
@@ -7458,6 +7486,10 @@
 	char uri[256] = "";
 	char cnonce[80];
 	char iabuf[INET_ADDRSTRLEN];
+	char *username;
+	char *secret;
+	char *md5secret;
+	struct sip_auth *auth = (struct sip_auth *) NULL;	/* Realm authentication */
 
 	if (!ast_strlen_zero(p->domain))
 		strncpy(uri, p->domain, sizeof(uri) - 1);
@@ -7468,10 +7500,25 @@
 
 	snprintf(cnonce, sizeof(cnonce), "%08x", rand());
 
-	snprintf(a1,sizeof(a1),"%s:%s:%s",p->authname,p->realm,p->peersecret);
+ 	/* Check if we have separate auth credentials */
+ 	if ((auth = find_realm_authentication(authl, p->realm))) {
+ 		username = auth->username;
+ 		secret = auth->secret;
+ 		md5secret = auth->md5secret;
+ 		ast_log(LOG_NOTICE,"Using realm %s authentication for this call\n", p->realm);
+ 	} else {
+ 		/* No authentication, use peer or register= config */
+ 		username = p->authname;
+ 		secret =  p->peersecret;
+ 		md5secret = p->peermd5secret;
+ 	}
+ 
+
+ 	/* Calculate SIP digest response */
+ 	snprintf(a1,sizeof(a1),"%s:%s:%s",username,p->realm,secret);
 	snprintf(a2,sizeof(a2),"%s:%s", sip_methods[method].text, uri);
-	if (!ast_strlen_zero(p->peermd5secret))
-	        strncpy(a1_hash, p->peermd5secret, sizeof(a1_hash) - 1);
+	if (!ast_strlen_zero(md5secret))
+	        strncpy(a1_hash, md5secret, sizeof(a1_hash) - 1);
 	else
 	        ast_md5_hash(a1_hash,a1);
 	ast_md5_hash(a2_hash,a2);
@@ -7484,9 +7531,9 @@
 	ast_md5_hash(resp_hash,resp);
 	/* XXX We hard code our qop to "auth" for now.  XXX */
 	if (!ast_strlen_zero(p->qop))
-		snprintf(digest,digest_len,"Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\", qop=\"%s\", cnonce=\"%s\", nc=%s",p->authname,p->realm,uri,p->nonce,resp_hash, p->opaque, "auth", cnonce, "00000001");
+		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\", qop=\"%s\", cnonce=\"%s\", nc=%s", username, p->realm, uri, p->nonce, resp_hash, p->opaque, "auth", cnonce, "00000001");
 	else
-		snprintf(digest,digest_len,"Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\"",p->authname,p->realm,uri,p->nonce,resp_hash, p->opaque);
+		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\"", username, p->realm, uri, p->nonce, resp_hash, p->opaque);
 
 	return 0;
 }
@@ -9525,6 +9572,105 @@
 	return res;
 }
 
+/*--- add_realm_authentication: Add realm authentication in list ---*/
+static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno)
+{
+        char authcopy[256] = "";
+        char *username=NULL, *realm=NULL, *secret=NULL, *md5secret=NULL;
+	char *stringp;
+	struct sip_auth *auth;
+	struct sip_auth *b = NULL, *a = authlist;
+                 
+        if (!configuration || ast_strlen_zero(configuration))
+                return (authlist);
+
+	ast_log(LOG_DEBUG, "Auth config ::  %s\n", configuration);
+
+        strncpy(authcopy, configuration, sizeof(authcopy)-1);
+        stringp = authcopy;
+
+        username = stringp;
+        realm = strrchr(stringp, '@');
+        if (realm) {
+                *realm = '\0';
+                realm++;
+        }
+        if (!username || ast_strlen_zero(username) || !realm || ast_strlen_zero(realm)) {
+                ast_log(LOG_WARNING, "Format for authentication entry is user[:secret]@realm at line %d", lineno);
+                return (authlist);
+        }
+        stringp = username;
+        username = strsep(&stringp, ":");
+        if (username) {
+                secret = strsep(&stringp, ":");
+		if (!secret) {
+        		stringp = username;
+			md5secret = strsep(&stringp,"#");
+		}
+        }
+	auth = malloc(sizeof(struct sip_auth));
+        if (auth) {
+                memset(auth, 0, sizeof(struct sip_auth));
+		strncpy(auth->realm, realm, sizeof(auth->realm)-1);
+		strncpy(auth->username, username, sizeof(auth->username)-1);
+		if (secret)
+			strncpy(auth->secret, secret, sizeof(auth->secret)-1);
+		if (md5secret)
+			strncpy(auth->md5secret, md5secret, sizeof(auth->md5secret)-1);
+        } else {
+                ast_log(LOG_ERROR, "Allocation of auth structure failed, Out of memory\n");
+                return (authlist);
+        }
+
+	/* Add authentication to authl */
+	if (!authlist) {	/* No existing list */
+		return(auth);
+	} else {
+		while(a) {
+			b = a;
+			a = a->next;
+		}
+		b->next = auth;	/* Add structure add end of list */
+	}
+
+	if (option_verbose > 2)
+		ast_verbose("Added authentication for realm %s\n", realm);
+
+        return(authlist);
+
+}
+
+/*--- clear_realm_authentication: Clear realm authentication list (at reload) ---*/
+static int clear_realm_authentication(struct sip_auth *authlist)
+{
+	struct sip_auth *a = authlist;
+	struct sip_auth *b;
+
+        while(a) {
+                b = a;
+                a = a->next;
+                free(b);
+        }
+
+
+	return(1);
+}
+
+/*--- find_realm_authentication: Find authentication for a specific realm ---*/
+static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, char *realm)
+{
+	struct sip_auth *a = authlist; 	/* First entry in auth list */
+
+	while (a) {
+		if (!strcasecmp(a->realm, realm)){
+			break;
+		}
+		a = a->next;
+	}
+	
+	return(a);
+}
+
 /*--- build_user: Initiate a SIP user structure from sip.conf ---*/
 static struct sip_user *build_user(const char *name, struct ast_variable *v, int realtime)
 {
@@ -9754,6 +9900,8 @@
 				strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
 			else if (!strcasecmp(v->name, "md5secret")) 
 				strncpy(peer->md5secret, v->value, sizeof(peer->md5secret)-1);
+			else if (!strcasecmp(v->name, "auth"))
+				peer->auth = add_realm_authentication(peer->auth, v->value, v->lineno);
 			else if (!strcasecmp(v->name, "callerid")) {
 				ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name), peer->cid_num, sizeof(peer->cid_num));
 			} else if (!strcasecmp(v->name, "context"))
@@ -10166,10 +10314,21 @@
 		 v = v->next;
 	}
 	
+	/* Build list of authentication to various SIP realms, i.e. service providers */
+ 	v = ast_variable_browse(cfg, "authentication");
+ 	while(v) {
+ 		/* Format for authentication is auth = username:password at realm */
+ 		if (!strcasecmp(v->name, "auth")) {
+ 			authl = add_realm_authentication(authl, v->value, v->lineno);
+ 		}
+ 		v = v->next;
+ 	}
+ 	
+	
 	/* Load peers, users and friends */
 	cat = ast_category_browse(cfg, NULL);
 	while(cat) {
-		if (strcasecmp(cat, "general")) {
+		if (strcasecmp(cat, "general") && strcasecmp(cat, "authentication")) {
 			utype = ast_variable_retrieve(cfg, cat, "type");
 			if (utype) {
 				if (!strcasecmp(utype, "user") || !strcasecmp(utype, "friend")) {
@@ -10611,6 +10770,9 @@
 /*--- sip_do_reload: Reload module */
 static int sip_do_reload(void)
 {
+	clear_realm_authentication(authl);
+	authl = (struct sip_auth *) NULL;
+
 	delete_users();
 	reload_config();
 	prune_peers();
@@ -10735,6 +10897,8 @@
 	ast_manager_unregister("SIPpeers");
 	ast_manager_unregister("SIPshowpeer");
 	ast_channel_unregister(&sip_tech);
+
+
 	if (!ast_mutex_lock(&iflock)) {
 		/* Hangup all interfaces if they have an owner */
 		p = iflist;
@@ -10787,6 +10951,8 @@
 	ASTOBJ_CONTAINER_DESTROY(&userl);
 	ASTOBJ_CONTAINER_DESTROY(&peerl);
 	ASTOBJ_CONTAINER_DESTROY(&regl);
+
+	clear_realm_authentication(authl);
 		
 	return 0;
 }




More information about the svn-commits mailing list