opensips/modules/uac/auth.c

changeset 16
c5c55937e44c
child 18
8ec65b8f6e2c
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/opensips/modules/uac/auth.c	Wed Feb 10 21:14:04 2010 +0100
     1.3 @@ -0,0 +1,468 @@
     1.4 +/*
     1.5 + * $Id: auth.c 5901 2009-07-21 07:45:05Z bogdan_iancu $
     1.6 + *
     1.7 + * Copyright (C) 2005 Voice Sistem SRL
     1.8 + *
     1.9 + * This file is part of opensips, a free SIP server.
    1.10 + *
    1.11 + * UAC OpenSIPS-module is free software; you can redistribute it and/or
    1.12 + * modify it under the terms of the GNU General Public License
    1.13 + * as published by the Free Software Foundation; either version 2
    1.14 + * of the License, or (at your option) any later version.
    1.15 + *
    1.16 + * UAC OpenSIPS-module is distributed in the hope that it will be useful,
    1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.19 + * GNU General Public License for more details.
    1.20 + *
    1.21 + * You should have received a copy of the GNU General Public License
    1.22 + * along with this program; if not, write to the Free Software
    1.23 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    1.24 + *
    1.25 + *
    1.26 + * History:
    1.27 + * ---------
    1.28 + *  2005-01-31  first version (ramona)
    1.29 + *  2006-03-02  UAC authentication looks first in AVPs for credential (bogdan)
    1.30 + */
    1.31 +
    1.32 +
    1.33 +#include <ctype.h>
    1.34 +#include <string.h>
    1.35 +
    1.36 +#include "../../str.h"
    1.37 +#include "../../dprint.h"
    1.38 +#include "../../pvar.h"
    1.39 +#include "../../data_lump.h"
    1.40 +#include "../../mem/mem.h"
    1.41 +#include "../tm/tm_load.h"
    1.42 +
    1.43 +#include "auth.h"
    1.44 +#include "auth_alg.h"
    1.45 +#include "auth_hdr.h"
    1.46 +
    1.47 +
    1.48 +extern struct tm_binds uac_tmb;
    1.49 +extern pv_spec_t auth_username_spec;
    1.50 +extern pv_spec_t auth_realm_spec;
    1.51 +extern pv_spec_t auth_password_spec;
    1.52 +
    1.53 +
    1.54 +static struct uac_credential *crd_list = 0;
    1.55 +
    1.56 +
    1.57 +#define  duplicate_str(_strd, _strs, _error) \
    1.58 +	do { \
    1.59 +		_strd.s = (char*)pkg_malloc(_strs.len); \
    1.60 +		if (_strd.s==0) \
    1.61 +		{ \
    1.62 +			LM_ERR("no more pkg memory\n");\
    1.63 +			goto _error; \
    1.64 +		} \
    1.65 +		memcpy( _strd.s, _strs.s, _strs.len); \
    1.66 +		_strd.len = _strs.len; \
    1.67 +	}while(0)
    1.68 +
    1.69 +
    1.70 +#define WWW_AUTH_CODE       401
    1.71 +#define WWW_AUTH_HDR        "WWW-Authenticate"
    1.72 +#define WWW_AUTH_HDR_LEN    (sizeof(WWW_AUTH_HDR)-1)
    1.73 +#define PROXY_AUTH_CODE     407
    1.74 +#define PROXY_AUTH_HDR      "Proxy-Authenticate"
    1.75 +#define PROXY_AUTH_HDR_LEN  (sizeof(PROXY_AUTH_HDR)-1)
    1.76 +
    1.77 +static str nc = {"00000001", 8};
    1.78 +static str cnonce = {"o", 1};
    1.79 +
    1.80 +int has_credentials(void)
    1.81 +{
    1.82 +	return (crd_list!=0)?1:0;
    1.83 +}
    1.84 +
    1.85 +void free_credential(struct uac_credential *crd)
    1.86 +{
    1.87 +	if (crd)
    1.88 +	{
    1.89 +		if (crd->realm.s)
    1.90 +			pkg_free(crd->realm.s);
    1.91 +		if (crd->user.s)
    1.92 +			pkg_free(crd->user.s);
    1.93 +		if (crd->passwd.s)
    1.94 +			pkg_free(crd->passwd.s);
    1.95 +		pkg_free(crd);
    1.96 +	}
    1.97 +}
    1.98 +
    1.99 +
   1.100 +int add_credential( unsigned int type, void *val)
   1.101 +{
   1.102 +	struct uac_credential *crd;
   1.103 +	char *p;
   1.104 +	str foo;
   1.105 +
   1.106 +	p = (char*)val;
   1.107 +	crd = 0;
   1.108 +
   1.109 +	if (p==0 || *p==0)
   1.110 +		goto error;
   1.111 +
   1.112 +	crd = (struct uac_credential*)pkg_malloc(sizeof(struct uac_credential));
   1.113 +	if (crd==0)
   1.114 +	{
   1.115 +		LM_ERR("no more pkg mem\n");
   1.116 +		goto error;
   1.117 +	}
   1.118 +	memset( crd, 0, sizeof(struct uac_credential));
   1.119 +
   1.120 +	/*parse the user */
   1.121 +	while (*p && isspace((int)*p)) p++;
   1.122 +	foo.s = p;
   1.123 +	while (*p && *p!=':' && !isspace((int)*p)) p++;
   1.124 +	if (foo.s==p || *p==0)
   1.125 +		/* missing or empty user */
   1.126 +		goto parse_error;
   1.127 +	foo.len = p - foo.s;
   1.128 +	/* dulicate it */
   1.129 +	duplicate_str( crd->user, foo, error);
   1.130 +
   1.131 +	/* parse the ':' separator */
   1.132 +	while (*p && isspace((int)*p)) p++;
   1.133 +	if (*p!=':')
   1.134 +		goto parse_error;
   1.135 +	p++;
   1.136 +	while (*p && isspace((int)*p)) p++;
   1.137 +	if (*p==0)
   1.138 +		goto parse_error;
   1.139 +
   1.140 +	/*parse the realm */
   1.141 +	while (*p && isspace((int)*p)) p++;
   1.142 +	foo.s = p;
   1.143 +	while (*p && *p!=':' && !isspace((int)*p)) p++;
   1.144 +	if (foo.s==p || *p==0)
   1.145 +		/* missing or empty realm */
   1.146 +		goto parse_error;
   1.147 +	foo.len = p - foo.s;
   1.148 +	/* dulicate it */
   1.149 +	duplicate_str( crd->realm, foo, error);
   1.150 +
   1.151 +	/* parse the ':' separator */
   1.152 +	while (*p && isspace((int)*p)) p++;
   1.153 +	if (*p!=':')
   1.154 +		goto parse_error;
   1.155 +	p++;
   1.156 +	while (*p && isspace((int)*p)) p++;
   1.157 +	if (*p==0)
   1.158 +		goto parse_error;
   1.159 +
   1.160 +	/*parse the passwd */
   1.161 +	while (*p && isspace((int)*p)) p++;
   1.162 +	foo.s = p;
   1.163 +	while (*p && !isspace((int)*p)) p++;
   1.164 +	if (foo.s==p)
   1.165 +		/* missing or empty passwd */
   1.166 +		goto parse_error;
   1.167 +	foo.len = p - foo.s;
   1.168 +	/* dulicate it */
   1.169 +	duplicate_str( crd->passwd, foo, error);
   1.170 +
   1.171 +	/* end of string */
   1.172 +	while (*p && isspace((int)*p)) p++;
   1.173 +	if (*p!=0)
   1.174 +		goto parse_error;
   1.175 +
   1.176 +	/* link the new cred struct */
   1.177 +	crd->next = crd_list;
   1.178 +	crd_list = crd;
   1.179 +
   1.180 +	pkg_free(val);
   1.181 +	return 0;
   1.182 +parse_error:
   1.183 +		LM_ERR("parse error in <%s> "
   1.184 +		"around %ld\n", (char*)val, (long)(p-(char*)val));
   1.185 +error:
   1.186 +	if (crd)
   1.187 +		free_credential(crd);
   1.188 +	return -1;
   1.189 +}
   1.190 +
   1.191 +
   1.192 +void destroy_credentials(void)
   1.193 +{
   1.194 +	struct uac_credential *foo;
   1.195 +
   1.196 +	while (crd_list)
   1.197 +	{
   1.198 +		foo = crd_list;
   1.199 +		crd_list = crd_list->next;
   1.200 +		free_credential(foo);
   1.201 +	}
   1.202 +	crd_list = 0;
   1.203 +}
   1.204 +
   1.205 +
   1.206 +static inline struct hdr_field *get_autenticate_hdr(struct sip_msg *rpl,
   1.207 +																int rpl_code)
   1.208 +{
   1.209 +	struct hdr_field *hdr;
   1.210 +	str hdr_name;
   1.211 +
   1.212 +	/* what hdr should we look for */
   1.213 +	if (rpl_code==WWW_AUTH_CODE)
   1.214 +	{
   1.215 +		hdr_name.s = WWW_AUTH_HDR;
   1.216 +		hdr_name.len = WWW_AUTH_HDR_LEN;
   1.217 +	} else if (rpl_code==PROXY_AUTH_CODE) {
   1.218 +		hdr_name.s = PROXY_AUTH_HDR;
   1.219 +		hdr_name.len = PROXY_AUTH_HDR_LEN;
   1.220 +	} else {
   1.221 +		LM_ERR("reply is not an "
   1.222 +			"auth request\n");
   1.223 +		goto error;
   1.224 +	}
   1.225 +
   1.226 +	LM_DBG("looking for header \"%.*s\"\n",
   1.227 +		hdr_name.len, hdr_name.s);
   1.228 +
   1.229 +	/* search the auth hdr, but first parse them all */
   1.230 +	if (parse_headers( rpl, HDR_EOH_F, 0)<0)
   1.231 +	{
   1.232 +		LM_ERR("failed to parse reply\n");
   1.233 +		goto error;
   1.234 +	}
   1.235 +	hdr = get_header_by_name( rpl , hdr_name.s, hdr_name.len);
   1.236 +	if (hdr)
   1.237 +		return hdr;
   1.238 +
   1.239 +	LM_ERR("reply has no "
   1.240 +		"auth hdr (%.*s)\n", hdr_name.len, hdr_name.s);
   1.241 +error:
   1.242 +	return 0;
   1.243 +}
   1.244 +
   1.245 +
   1.246 +static inline struct uac_credential *lookup_realm( str *realm)
   1.247 +{
   1.248 +	struct uac_credential *crd;
   1.249 +
   1.250 +	for( crd=crd_list ; crd ; crd=crd->next )
   1.251 +		if (realm->len==crd->realm.len &&
   1.252 +		strncmp( realm->s, crd->realm.s, realm->len)==0 )
   1.253 +			return crd;
   1.254 +	return 0;
   1.255 +}
   1.256 +
   1.257 +
   1.258 +static inline struct uac_credential *get_avp_credential(struct sip_msg *msg,
   1.259 +																str *realm)
   1.260 +{
   1.261 +	static struct uac_credential crd;
   1.262 +	pv_value_t pv_val;
   1.263 +
   1.264 +	if(pv_get_spec_value( msg, &auth_realm_spec, &pv_val)!=0
   1.265 +	|| pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
   1.266 +		return 0;
   1.267 +	
   1.268 +	crd.realm = pv_val.rs;
   1.269 +	/* is it the domain we are looking for? */
   1.270 +	if (realm->len!=crd.realm.len ||
   1.271 +	strncmp( realm->s, crd.realm.s, realm->len)!=0 )
   1.272 +		return 0;
   1.273 +
   1.274 +	/* get username and password */
   1.275 +	if(pv_get_spec_value( msg, &auth_username_spec, &pv_val)!=0
   1.276 +	|| pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
   1.277 +		return 0;
   1.278 +	crd.user = pv_val.rs;
   1.279 +
   1.280 +	if(pv_get_spec_value( msg, &auth_password_spec, &pv_val)!=0
   1.281 +	|| pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
   1.282 +		return 0;
   1.283 +	crd.passwd = pv_val.rs;
   1.284 +
   1.285 +	return &crd;
   1.286 +}
   1.287 +
   1.288 +
   1.289 +static inline void do_uac_auth(struct sip_msg *req, str *uri,
   1.290 +		struct uac_credential *crd, struct authenticate_body *auth,
   1.291 +		HASHHEX response)
   1.292 +{
   1.293 +	HASHHEX ha1;
   1.294 +	HASHHEX ha2;
   1.295 +
   1.296 +	if((auth->flags&QOP_AUTH) || (auth->flags&QOP_AUTH_INT))
   1.297 +	{
   1.298 +		/* if qop generate nonce-count and cnonce */
   1.299 +		cnonce.s = int2str(core_hash(&auth->nonce, 0, 0),&cnonce.len);
   1.300 +
   1.301 +		/* do authentication */
   1.302 +		uac_calc_HA1( crd, auth, &cnonce, ha1);
   1.303 +		uac_calc_HA2( &req->first_line.u.request.method, uri,
   1.304 +			auth, 0/*hentity*/, ha2 );
   1.305 +
   1.306 +		uac_calc_response( ha1, ha2, auth, &nc, &cnonce, response);
   1.307 +		auth->nc = &nc;
   1.308 +		auth->cnonce = &cnonce;
   1.309 +	} else {
   1.310 +		/* do authentication */
   1.311 +		uac_calc_HA1( crd, auth, 0/*cnonce*/, ha1);
   1.312 +		uac_calc_HA2( &req->first_line.u.request.method, uri,
   1.313 +			auth, 0/*hentity*/, ha2 );
   1.314 +
   1.315 +		uac_calc_response( ha1, ha2, auth, 0/*nc*/, 0/*cnonce*/, response);
   1.316 +	}
   1.317 +}
   1.318 +
   1.319 +
   1.320 +static inline int apply_urihdr_changes( struct sip_msg *req,
   1.321 +													str *uri, str *hdr)
   1.322 +{
   1.323 +	struct lump* anchor;
   1.324 +
   1.325 +	/* add the uri - move it to branch directly FIXME (bogdan)*/
   1.326 +	if (req->new_uri.s)
   1.327 +	{
   1.328 +		pkg_free(req->new_uri.s);
   1.329 +		req->new_uri.len=0;
   1.330 +	}
   1.331 +	req->parsed_uri_ok=0;
   1.332 +	req->new_uri.s = (char*)pkg_malloc(uri->len+1);
   1.333 +	if (req->new_uri.s==0)
   1.334 +	{
   1.335 +		LM_ERR("no more pkg\n");
   1.336 +		goto error;
   1.337 +	}
   1.338 +	memcpy( req->new_uri.s, uri->s, uri->len);
   1.339 +	req->new_uri.s[uri->len]=0;
   1.340 +	req->new_uri.len=uri->len;
   1.341 +
   1.342 +	/* add the header */
   1.343 +	if (parse_headers(req, HDR_EOH_F, 0) == -1)
   1.344 +	{
   1.345 +		LM_ERR("failed to parse message\n");
   1.346 +		goto error;
   1.347 +	}
   1.348 +
   1.349 +	anchor = anchor_lump(req, req->unparsed - req->buf, 0, 0);
   1.350 +	if (anchor==0)
   1.351 +	{
   1.352 +		LM_ERR("failed to get anchor\n");
   1.353 +		goto error;
   1.354 +	}
   1.355 +
   1.356 +	if (insert_new_lump_before(anchor, hdr->s, hdr->len, 0) == 0)
   1.357 +	{
   1.358 +		LM_ERR("faield to insert lump\n");
   1.359 +		goto error;
   1.360 +	}
   1.361 +
   1.362 +	return 0;
   1.363 +error:
   1.364 +	pkg_free( hdr->s );
   1.365 +	return -1;
   1.366 +}
   1.367 +
   1.368 +
   1.369 +
   1.370 +int uac_auth( struct sip_msg *msg)
   1.371 +{
   1.372 +	static struct authenticate_body auth;
   1.373 +	struct uac_credential *crd;
   1.374 +	int code, branch;
   1.375 +	struct sip_msg *rpl;
   1.376 +	struct cell *t;
   1.377 +	struct hdr_field *hdr;
   1.378 +	HASHHEX response;
   1.379 +	str *new_hdr;
   1.380 +
   1.381 +	/* get transaction */
   1.382 +	t = uac_tmb.t_gett();
   1.383 +	if (t==T_UNDEFINED || t==T_NULL_CELL)
   1.384 +	{
   1.385 +		LM_CRIT("no current transaction found\n");
   1.386 +		goto error;
   1.387 +	}
   1.388 +
   1.389 +	/* get the selected branch */
   1.390 +	branch = uac_tmb.t_get_picked();
   1.391 +	if (branch<0) {
   1.392 +		LM_CRIT("no picked branch (%d)\n",branch);
   1.393 +		goto error;
   1.394 +	}
   1.395 +
   1.396 +	rpl = t->uac[branch].reply;
   1.397 +	code = t->uac[branch].last_received;
   1.398 +	LM_DBG("picked reply is %p, code %d\n",rpl,code);
   1.399 +
   1.400 +	if (rpl==0)
   1.401 +	{
   1.402 +		LM_CRIT("empty reply on picked branch\n");
   1.403 +		goto error;
   1.404 +	}
   1.405 +	if (rpl==FAKED_REPLY)
   1.406 +	{
   1.407 +		LM_ERR("cannot process a FAKED reply\n");
   1.408 +		goto error;
   1.409 +	}
   1.410 +
   1.411 +	hdr = get_autenticate_hdr( rpl, code);
   1.412 +	if (hdr==0)
   1.413 +	{
   1.414 +		LM_ERR("failed to extract authenticate hdr\n");
   1.415 +		goto error;
   1.416 +	}
   1.417 +
   1.418 +	LM_DBG("header found; body=<%.*s>\n",
   1.419 +		hdr->body.len, hdr->body.s);
   1.420 +
   1.421 +	if (parse_authenticate_body( &hdr->body, &auth)<0)
   1.422 +	{
   1.423 +		LM_ERR("failed to parse auth hdr body\n");
   1.424 +		goto error;
   1.425 +	}
   1.426 +
   1.427 +	/* can we authenticate this realm? */
   1.428 +	crd = 0;
   1.429 +	/* first look into AVP, if set */
   1.430 +	if ( auth_realm_spec.type==PVT_AVP )
   1.431 +		crd = get_avp_credential( msg, &auth.realm );
   1.432 +	/* if not found, look into predefined credentials */
   1.433 +	if (crd==0)
   1.434 +		crd = lookup_realm( &auth.realm );
   1.435 +	/* found? */
   1.436 +	if (crd==0)
   1.437 +	{
   1.438 +		LM_DBG("no credential for realm \"%.*s\"\n",
   1.439 +			auth.realm.len, auth.realm.s);
   1.440 +		goto error;
   1.441 +	}
   1.442 +
   1.443 +	/* do authentication */
   1.444 +	do_uac_auth( msg, &t->uac[branch].uri, crd, &auth, response);
   1.445 +
   1.446 +	/* build the authorization header */
   1.447 +	new_hdr = build_authorization_hdr( code, &t->uac[branch].uri,
   1.448 +		crd, &auth, response);
   1.449 +	if (new_hdr==0)
   1.450 +	{
   1.451 +		LM_ERR("failed to build authorization hdr\n");
   1.452 +		goto error;
   1.453 +	}
   1.454 +
   1.455 +	/* so far, so good -> add the header and set the proper RURI */
   1.456 +	if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 )
   1.457 +	{
   1.458 +		LM_ERR("failed to apply changes\n");
   1.459 +		goto error;
   1.460 +	}
   1.461 +
   1.462 +	/* increas the Cseq nr */
   1.463 +
   1.464 +
   1.465 +	return 0;
   1.466 +error:
   1.467 +	return -1;
   1.468 +}
   1.469 +
   1.470 +
   1.471 +

mercurial