opensips/modules/uac/auth.c

Wed, 10 Feb 2010 21:14:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 10 Feb 2010 21:14:04 +0100
changeset 16
c5c55937e44c
child 18
8ec65b8f6e2c
permissions
-rw-r--r--

Import unmodified vendor sources for correction and improvement.

     1 /*
     2  * $Id: auth.c 5901 2009-07-21 07:45:05Z bogdan_iancu $
     3  *
     4  * Copyright (C) 2005 Voice Sistem SRL
     5  *
     6  * This file is part of opensips, a free SIP server.
     7  *
     8  * UAC OpenSIPS-module is free software; you can redistribute it and/or
     9  * modify it under the terms of the GNU General Public License
    10  * as published by the Free Software Foundation; either version 2
    11  * of the License, or (at your option) any later version.
    12  *
    13  * UAC OpenSIPS-module is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  *
    18  * You should have received a copy of the GNU General Public License
    19  * along with this program; if not, write to the Free Software
    20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    21  *
    22  *
    23  * History:
    24  * ---------
    25  *  2005-01-31  first version (ramona)
    26  *  2006-03-02  UAC authentication looks first in AVPs for credential (bogdan)
    27  */
    30 #include <ctype.h>
    31 #include <string.h>
    33 #include "../../str.h"
    34 #include "../../dprint.h"
    35 #include "../../pvar.h"
    36 #include "../../data_lump.h"
    37 #include "../../mem/mem.h"
    38 #include "../tm/tm_load.h"
    40 #include "auth.h"
    41 #include "auth_alg.h"
    42 #include "auth_hdr.h"
    45 extern struct tm_binds uac_tmb;
    46 extern pv_spec_t auth_username_spec;
    47 extern pv_spec_t auth_realm_spec;
    48 extern pv_spec_t auth_password_spec;
    51 static struct uac_credential *crd_list = 0;
    54 #define  duplicate_str(_strd, _strs, _error) \
    55 	do { \
    56 		_strd.s = (char*)pkg_malloc(_strs.len); \
    57 		if (_strd.s==0) \
    58 		{ \
    59 			LM_ERR("no more pkg memory\n");\
    60 			goto _error; \
    61 		} \
    62 		memcpy( _strd.s, _strs.s, _strs.len); \
    63 		_strd.len = _strs.len; \
    64 	}while(0)
    67 #define WWW_AUTH_CODE       401
    68 #define WWW_AUTH_HDR        "WWW-Authenticate"
    69 #define WWW_AUTH_HDR_LEN    (sizeof(WWW_AUTH_HDR)-1)
    70 #define PROXY_AUTH_CODE     407
    71 #define PROXY_AUTH_HDR      "Proxy-Authenticate"
    72 #define PROXY_AUTH_HDR_LEN  (sizeof(PROXY_AUTH_HDR)-1)
    74 static str nc = {"00000001", 8};
    75 static str cnonce = {"o", 1};
    77 int has_credentials(void)
    78 {
    79 	return (crd_list!=0)?1:0;
    80 }
    82 void free_credential(struct uac_credential *crd)
    83 {
    84 	if (crd)
    85 	{
    86 		if (crd->realm.s)
    87 			pkg_free(crd->realm.s);
    88 		if (crd->user.s)
    89 			pkg_free(crd->user.s);
    90 		if (crd->passwd.s)
    91 			pkg_free(crd->passwd.s);
    92 		pkg_free(crd);
    93 	}
    94 }
    97 int add_credential( unsigned int type, void *val)
    98 {
    99 	struct uac_credential *crd;
   100 	char *p;
   101 	str foo;
   103 	p = (char*)val;
   104 	crd = 0;
   106 	if (p==0 || *p==0)
   107 		goto error;
   109 	crd = (struct uac_credential*)pkg_malloc(sizeof(struct uac_credential));
   110 	if (crd==0)
   111 	{
   112 		LM_ERR("no more pkg mem\n");
   113 		goto error;
   114 	}
   115 	memset( crd, 0, sizeof(struct uac_credential));
   117 	/*parse the user */
   118 	while (*p && isspace((int)*p)) p++;
   119 	foo.s = p;
   120 	while (*p && *p!=':' && !isspace((int)*p)) p++;
   121 	if (foo.s==p || *p==0)
   122 		/* missing or empty user */
   123 		goto parse_error;
   124 	foo.len = p - foo.s;
   125 	/* dulicate it */
   126 	duplicate_str( crd->user, foo, error);
   128 	/* parse the ':' separator */
   129 	while (*p && isspace((int)*p)) p++;
   130 	if (*p!=':')
   131 		goto parse_error;
   132 	p++;
   133 	while (*p && isspace((int)*p)) p++;
   134 	if (*p==0)
   135 		goto parse_error;
   137 	/*parse the realm */
   138 	while (*p && isspace((int)*p)) p++;
   139 	foo.s = p;
   140 	while (*p && *p!=':' && !isspace((int)*p)) p++;
   141 	if (foo.s==p || *p==0)
   142 		/* missing or empty realm */
   143 		goto parse_error;
   144 	foo.len = p - foo.s;
   145 	/* dulicate it */
   146 	duplicate_str( crd->realm, foo, error);
   148 	/* parse the ':' separator */
   149 	while (*p && isspace((int)*p)) p++;
   150 	if (*p!=':')
   151 		goto parse_error;
   152 	p++;
   153 	while (*p && isspace((int)*p)) p++;
   154 	if (*p==0)
   155 		goto parse_error;
   157 	/*parse the passwd */
   158 	while (*p && isspace((int)*p)) p++;
   159 	foo.s = p;
   160 	while (*p && !isspace((int)*p)) p++;
   161 	if (foo.s==p)
   162 		/* missing or empty passwd */
   163 		goto parse_error;
   164 	foo.len = p - foo.s;
   165 	/* dulicate it */
   166 	duplicate_str( crd->passwd, foo, error);
   168 	/* end of string */
   169 	while (*p && isspace((int)*p)) p++;
   170 	if (*p!=0)
   171 		goto parse_error;
   173 	/* link the new cred struct */
   174 	crd->next = crd_list;
   175 	crd_list = crd;
   177 	pkg_free(val);
   178 	return 0;
   179 parse_error:
   180 		LM_ERR("parse error in <%s> "
   181 		"around %ld\n", (char*)val, (long)(p-(char*)val));
   182 error:
   183 	if (crd)
   184 		free_credential(crd);
   185 	return -1;
   186 }
   189 void destroy_credentials(void)
   190 {
   191 	struct uac_credential *foo;
   193 	while (crd_list)
   194 	{
   195 		foo = crd_list;
   196 		crd_list = crd_list->next;
   197 		free_credential(foo);
   198 	}
   199 	crd_list = 0;
   200 }
   203 static inline struct hdr_field *get_autenticate_hdr(struct sip_msg *rpl,
   204 																int rpl_code)
   205 {
   206 	struct hdr_field *hdr;
   207 	str hdr_name;
   209 	/* what hdr should we look for */
   210 	if (rpl_code==WWW_AUTH_CODE)
   211 	{
   212 		hdr_name.s = WWW_AUTH_HDR;
   213 		hdr_name.len = WWW_AUTH_HDR_LEN;
   214 	} else if (rpl_code==PROXY_AUTH_CODE) {
   215 		hdr_name.s = PROXY_AUTH_HDR;
   216 		hdr_name.len = PROXY_AUTH_HDR_LEN;
   217 	} else {
   218 		LM_ERR("reply is not an "
   219 			"auth request\n");
   220 		goto error;
   221 	}
   223 	LM_DBG("looking for header \"%.*s\"\n",
   224 		hdr_name.len, hdr_name.s);
   226 	/* search the auth hdr, but first parse them all */
   227 	if (parse_headers( rpl, HDR_EOH_F, 0)<0)
   228 	{
   229 		LM_ERR("failed to parse reply\n");
   230 		goto error;
   231 	}
   232 	hdr = get_header_by_name( rpl , hdr_name.s, hdr_name.len);
   233 	if (hdr)
   234 		return hdr;
   236 	LM_ERR("reply has no "
   237 		"auth hdr (%.*s)\n", hdr_name.len, hdr_name.s);
   238 error:
   239 	return 0;
   240 }
   243 static inline struct uac_credential *lookup_realm( str *realm)
   244 {
   245 	struct uac_credential *crd;
   247 	for( crd=crd_list ; crd ; crd=crd->next )
   248 		if (realm->len==crd->realm.len &&
   249 		strncmp( realm->s, crd->realm.s, realm->len)==0 )
   250 			return crd;
   251 	return 0;
   252 }
   255 static inline struct uac_credential *get_avp_credential(struct sip_msg *msg,
   256 																str *realm)
   257 {
   258 	static struct uac_credential crd;
   259 	pv_value_t pv_val;
   261 	if(pv_get_spec_value( msg, &auth_realm_spec, &pv_val)!=0
   262 	|| pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
   263 		return 0;
   265 	crd.realm = pv_val.rs;
   266 	/* is it the domain we are looking for? */
   267 	if (realm->len!=crd.realm.len ||
   268 	strncmp( realm->s, crd.realm.s, realm->len)!=0 )
   269 		return 0;
   271 	/* get username and password */
   272 	if(pv_get_spec_value( msg, &auth_username_spec, &pv_val)!=0
   273 	|| pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
   274 		return 0;
   275 	crd.user = pv_val.rs;
   277 	if(pv_get_spec_value( msg, &auth_password_spec, &pv_val)!=0
   278 	|| pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
   279 		return 0;
   280 	crd.passwd = pv_val.rs;
   282 	return &crd;
   283 }
   286 static inline void do_uac_auth(struct sip_msg *req, str *uri,
   287 		struct uac_credential *crd, struct authenticate_body *auth,
   288 		HASHHEX response)
   289 {
   290 	HASHHEX ha1;
   291 	HASHHEX ha2;
   293 	if((auth->flags&QOP_AUTH) || (auth->flags&QOP_AUTH_INT))
   294 	{
   295 		/* if qop generate nonce-count and cnonce */
   296 		cnonce.s = int2str(core_hash(&auth->nonce, 0, 0),&cnonce.len);
   298 		/* do authentication */
   299 		uac_calc_HA1( crd, auth, &cnonce, ha1);
   300 		uac_calc_HA2( &req->first_line.u.request.method, uri,
   301 			auth, 0/*hentity*/, ha2 );
   303 		uac_calc_response( ha1, ha2, auth, &nc, &cnonce, response);
   304 		auth->nc = &nc;
   305 		auth->cnonce = &cnonce;
   306 	} else {
   307 		/* do authentication */
   308 		uac_calc_HA1( crd, auth, 0/*cnonce*/, ha1);
   309 		uac_calc_HA2( &req->first_line.u.request.method, uri,
   310 			auth, 0/*hentity*/, ha2 );
   312 		uac_calc_response( ha1, ha2, auth, 0/*nc*/, 0/*cnonce*/, response);
   313 	}
   314 }
   317 static inline int apply_urihdr_changes( struct sip_msg *req,
   318 													str *uri, str *hdr)
   319 {
   320 	struct lump* anchor;
   322 	/* add the uri - move it to branch directly FIXME (bogdan)*/
   323 	if (req->new_uri.s)
   324 	{
   325 		pkg_free(req->new_uri.s);
   326 		req->new_uri.len=0;
   327 	}
   328 	req->parsed_uri_ok=0;
   329 	req->new_uri.s = (char*)pkg_malloc(uri->len+1);
   330 	if (req->new_uri.s==0)
   331 	{
   332 		LM_ERR("no more pkg\n");
   333 		goto error;
   334 	}
   335 	memcpy( req->new_uri.s, uri->s, uri->len);
   336 	req->new_uri.s[uri->len]=0;
   337 	req->new_uri.len=uri->len;
   339 	/* add the header */
   340 	if (parse_headers(req, HDR_EOH_F, 0) == -1)
   341 	{
   342 		LM_ERR("failed to parse message\n");
   343 		goto error;
   344 	}
   346 	anchor = anchor_lump(req, req->unparsed - req->buf, 0, 0);
   347 	if (anchor==0)
   348 	{
   349 		LM_ERR("failed to get anchor\n");
   350 		goto error;
   351 	}
   353 	if (insert_new_lump_before(anchor, hdr->s, hdr->len, 0) == 0)
   354 	{
   355 		LM_ERR("faield to insert lump\n");
   356 		goto error;
   357 	}
   359 	return 0;
   360 error:
   361 	pkg_free( hdr->s );
   362 	return -1;
   363 }
   367 int uac_auth( struct sip_msg *msg)
   368 {
   369 	static struct authenticate_body auth;
   370 	struct uac_credential *crd;
   371 	int code, branch;
   372 	struct sip_msg *rpl;
   373 	struct cell *t;
   374 	struct hdr_field *hdr;
   375 	HASHHEX response;
   376 	str *new_hdr;
   378 	/* get transaction */
   379 	t = uac_tmb.t_gett();
   380 	if (t==T_UNDEFINED || t==T_NULL_CELL)
   381 	{
   382 		LM_CRIT("no current transaction found\n");
   383 		goto error;
   384 	}
   386 	/* get the selected branch */
   387 	branch = uac_tmb.t_get_picked();
   388 	if (branch<0) {
   389 		LM_CRIT("no picked branch (%d)\n",branch);
   390 		goto error;
   391 	}
   393 	rpl = t->uac[branch].reply;
   394 	code = t->uac[branch].last_received;
   395 	LM_DBG("picked reply is %p, code %d\n",rpl,code);
   397 	if (rpl==0)
   398 	{
   399 		LM_CRIT("empty reply on picked branch\n");
   400 		goto error;
   401 	}
   402 	if (rpl==FAKED_REPLY)
   403 	{
   404 		LM_ERR("cannot process a FAKED reply\n");
   405 		goto error;
   406 	}
   408 	hdr = get_autenticate_hdr( rpl, code);
   409 	if (hdr==0)
   410 	{
   411 		LM_ERR("failed to extract authenticate hdr\n");
   412 		goto error;
   413 	}
   415 	LM_DBG("header found; body=<%.*s>\n",
   416 		hdr->body.len, hdr->body.s);
   418 	if (parse_authenticate_body( &hdr->body, &auth)<0)
   419 	{
   420 		LM_ERR("failed to parse auth hdr body\n");
   421 		goto error;
   422 	}
   424 	/* can we authenticate this realm? */
   425 	crd = 0;
   426 	/* first look into AVP, if set */
   427 	if ( auth_realm_spec.type==PVT_AVP )
   428 		crd = get_avp_credential( msg, &auth.realm );
   429 	/* if not found, look into predefined credentials */
   430 	if (crd==0)
   431 		crd = lookup_realm( &auth.realm );
   432 	/* found? */
   433 	if (crd==0)
   434 	{
   435 		LM_DBG("no credential for realm \"%.*s\"\n",
   436 			auth.realm.len, auth.realm.s);
   437 		goto error;
   438 	}
   440 	/* do authentication */
   441 	do_uac_auth( msg, &t->uac[branch].uri, crd, &auth, response);
   443 	/* build the authorization header */
   444 	new_hdr = build_authorization_hdr( code, &t->uac[branch].uri,
   445 		crd, &auth, response);
   446 	if (new_hdr==0)
   447 	{
   448 		LM_ERR("failed to build authorization hdr\n");
   449 		goto error;
   450 	}
   452 	/* so far, so good -> add the header and set the proper RURI */
   453 	if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 )
   454 	{
   455 		LM_ERR("failed to apply changes\n");
   456 		goto error;
   457 	}
   459 	/* increas the Cseq nr */
   462 	return 0;
   463 error:
   464 	return -1;
   465 }

mercurial