Selaa lähdekoodia

auth_radius(s), avp_radius(s), uri_radius(s): revived

Revive modules_/{auth_radius,avp_radius,uri_radius}.
Needed to be able to use radius auth.  with ser auth_api/module
(the ser and kamailio auth apis are not compatible and so one
cannot use a kamailio radius auth with the ser auth module).

Reverts 456c3c137e9abcf687413f9675fe0f1761ce820d.
Andrei Pelinescu-Onciul 15 vuotta sitten
vanhempi
commit
b06131c655

+ 17 - 0
modules_s/auth_radius/Makefile

@@ -0,0 +1,17 @@
+# $Id$
+#
+# Digest Authentication - Radius support
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+include ../../Makefile.radius
+
+auto_gen=
+NAME=auth_radius.so
+
+
+DEFS+=-DSER_MOD_INTERFACE
+
+include ../../Makefile.modules

+ 189 - 0
modules_s/auth_radius/README

@@ -0,0 +1,189 @@
+
+Auth_radius Module
+
+Jan Janak
+
+   FhG Fokus
+
+Juha Heinanen
+
+   Song Networks
+
+Stelios Sidiroglou-Douskos
+
+Edited by
+
+Jan Janak
+
+   Copyright © 2002, 2003 FhG FOKUS
+     _________________________________________________________
+
+   Table of Contents
+   1. User's Guide
+
+        1.1. Overview
+        1.2. Dependencies
+        1.3. Exported Parameters
+
+              1.3.1. radius_config (string)
+              1.3.2. service_type (integer)
+
+        1.4. Exported Functions
+
+              1.4.1. radius_www_authorize(realm)
+              1.4.2. radius_proxy_authorize(realm)
+
+   2. Developer's Guide
+   3. Frequently Asked Questions
+
+   List of Examples
+   1-1. radius_config parameter usage
+   1-2. radius_config usage
+   1-3. radius_www_authorize usage
+   1-4. proxy_authorize usage
+     _________________________________________________________
+
+Chapter 1. User's Guide
+
+1.1. Overview
+
+   This module contains functions that are used to perform
+   authentication using a Radius server. Basically the proxy will
+   pass along the credentials to the radius server which will in
+   turn send a reply containing result of the authentication. So
+   basically the whole authentication is done in the Radius
+   server. Before sending the request to the radius server we
+   perform some sanity checks over the credentials to make sure
+   that only well formed credentials will get to the server. We
+   have implemented radius authentication according to
+   draft-sterman-aaa-sip-00. This module requires radiusclient
+   library version 0.4.1 or higher which is available from
+   http://developer.berlios.de/projects/radiusclient-ng/.
+
+   How to configure radius server -- more detailed description --
+   TBD.
+
+   Warning
+
+   The detailed description of radius authentication setup is
+   important since many people will use it and we want to make
+   the setup painless.
+     _________________________________________________________
+
+1.2. Dependencies
+
+   The module depends on the following modules (in the other
+   words the listed modules must be loaded before this module):
+
+     * auth -- Generic authentication functions
+     _________________________________________________________
+
+1.3. Exported Parameters
+
+1.3.1. radius_config (string)
+
+   This is the location of the configuration file of radius
+   client libraries.
+
+   Default value is
+   "/usr/local/etc/radiusclient/radiusclient.conf".
+
+   Example 1-1. radius_config parameter usage
+modparam("auth_radius", "radius_config", "/etc/radiusclient.conf")
+     _________________________________________________________
+
+1.3.2. service_type (integer)
+
+   This is the value of the Service-Type radius attribute to be
+   used. The default should be fine for most people. See your
+   radius client include files for numbers to be put in this
+   parameter if you need to change it.
+
+   Default value is "15".
+
+   Example 1-2. radius_config usage
+modparam("auth_radius", "service_type", 15)
+     _________________________________________________________
+
+1.4. Exported Functions
+
+1.4.1. radius_www_authorize(realm)
+
+   The function verifies credentials according to RFC2617. If the
+   credentials are verified successfully then the function will
+   succeed and mark the credentials as authorized (marked
+   credentials can be later used by some other functions). If the
+   function was unable to verify the credentials for some reason
+   then it will fail and the script should call www_challenge
+   which will challenge the user again.
+
+   This function will, in fact, perform sanity checks over the
+   received credentials and then pass them along to the radius
+   server which will verify the credentials and return whether
+   they are valid or not.
+
+   Meaning of the parameter is as follows:
+
+     * realm - Realm is a opaque string that the user agent
+       should present to the user so he can decide what username
+       and password to use. Usually this is domain of the host
+       the server is running on.
+       If an empty string "" is used then the server will
+       generate it from the request. In case of REGISTER requests
+       To header field domain will be used (because this header
+       field represents a user being registered), for all other
+       messages From header field domain will be used.
+
+   Example 1-3. radius_www_authorize usage
+...
+if (!radius_www_authorize("iptel.org")) {
+    www_challenge("iptel.org", "1");
+};
+...
+     _________________________________________________________
+
+1.4.2. radius_proxy_authorize(realm)
+
+   The function verifies credentials according to RFC2617. If the
+   credentials are verified successfully then the function will
+   succeed and mark the credentials as authorized (marked
+   credentials can be later used by some other functions). If the
+   function was unable to verify the credentials for some reason
+   then it will fail and the script should call proxy_challenge
+   which will challenge the user again.
+
+   This function will, in fact, perform sanity checks over the
+   received credentials and then pass them along to the radius
+   server which will verify the credentials and return whether
+   they are valid or not.
+
+   Meaning of the parameter is as follows:
+
+     * realm - Realm is a opaque string that the user agent
+       should present to the user so he can decide what username
+       and password to use. Usually this is domain of the host
+       the server is running on.
+       If an empty string "" is used then the server will
+       generate it from the request. From header field domain
+       will be used as realm.
+
+   Example 1-4. proxy_authorize usage
+...
+if (!radius_proxy_authorize("")) {
+    proxy_challenge("", "1");  # Realm will be autogenerated
+};
+...
+     _________________________________________________________
+
+Chapter 2. Developer's Guide
+
+   To be done.
+     _________________________________________________________
+
+Chapter 3. Frequently Asked Questions
+
+   3.1. What is the meaning of life ?
+
+   3.1. What is the meaning of life ?
+
+   42

+ 302 - 0
modules_s/auth_radius/authorize.c

@@ -0,0 +1,302 @@
+/*
+ * $Id$
+ *
+ * Digest Authentication - Radius support
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * -------
+ * 2003-03-09: Based on authorize.c from radius_auth (janakj)
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include "../../mem/mem.h"
+#include "../../str.h"
+#include "../../sr_module.h"
+#include "../../parser/hf.h"
+#include "../../parser/digest/digest.h"
+#include "../../parser/parse_uri.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_to.h"
+#include "../../dprint.h"
+#include "../../id.h"
+#include "../../ut.h"
+#include "../auth/api.h"
+#include "authorize.h"
+#include "sterman.h"
+#include "authrad_mod.h"
+
+
+static void attr_name_value(str* name, str* value, VALUE_PAIR* vp)
+{
+    int i;
+    
+    for (i = 0; i < vp->lvalue; i++) {
+	if (vp->strvalue[i] == ':' || vp->strvalue[i] == '=') {
+	    name->s = vp->strvalue;
+	    name->len = i;
+	    
+	    if (i == (vp->lvalue - 1)) {
+		value->s = (char*)0;
+		value->len = 0;
+	    } else {
+		value->s = vp->strvalue + i + 1;
+		value->len = vp->lvalue - i - 1;
+	    }
+	    return;
+	}
+    }
+
+    name->len = value->len = 0;
+    name->s = value->s = (char*)0;
+}
+
+
+/*
+ * Generate AVPs from the database result
+ */
+static int generate_avps(VALUE_PAIR* received)
+{
+	int_str name, val;
+	VALUE_PAIR *vp;
+	
+	vp = rc_avpair_get(received, ATTRID(attrs[A_SER_UID].v), VENDOR(attrs[A_SER_UID].v));
+	if (vp == NULL) {
+	    WARN("RADIUS server did not send SER-UID attribute in digest authentication reply\n");
+	    return -1;
+	}
+	val.s.len = vp->lvalue;
+	val.s.s = vp->strvalue;
+	name.s.s = "uid";
+	name.s.len = 3;
+
+	if (add_avp(AVP_TRACK_FROM | AVP_CLASS_USER | AVP_NAME_STR | AVP_VAL_STR, name, val) < 0) {
+	    ERR("Unable to create UID attribute\n");
+	    return -1;
+	}
+
+	vp = received;
+	while ((vp = rc_avpair_get(vp, ATTRID(attrs[A_SER_ATTR].v), VENDOR(attrs[A_SER_ATTR].v)))) {
+		attr_name_value(&name.s, &val.s, vp);
+		if (name.s.len == 0) {
+		    ERR("Missing attribute name\n");
+		    return -1;
+		}
+		
+		if (add_avp(AVP_TRACK_FROM | AVP_CLASS_USER | AVP_NAME_STR | AVP_VAL_STR, name, val) < 0) {
+			LOG(L_ERR, "generate_avps: Unable to create a new AVP\n");
+			return -1;
+		} else {
+			DBG("generate_avps: AVP '%.*s'='%.*s' has been added\n",
+			    name.s.len, ZSW(name.s.s), 
+			    val.s.len, ZSW(val.s.s));
+		}
+		vp = vp->next;
+	}
+	
+	return 0;
+}
+
+
+
+
+/* 
+ * Extract URI depending on the request from To or From header 
+ */
+static inline int get_uri(struct sip_msg* _m, str** _uri)
+{
+	if ((REQ_LINE(_m).method.len == 8) && (memcmp(REQ_LINE(_m).method.s, "REGISTER", 8) == 0)) {
+		if (!_m->to && ((parse_headers(_m, HDR_TO_F, 0) == -1) || !_m->to)) {
+			LOG(L_ERR, "get_uri(): To header field not found or malformed\n");
+			return -1;
+		}
+		*_uri = &(get_to(_m)->uri);
+	} else {
+		if (parse_from_header(_m) == -1) {
+			LOG(L_ERR, "get_uri(): Error while parsing headers\n");
+			return -2;
+		}
+		*_uri = &(get_from(_m)->uri);
+	}
+	return 0;
+}
+
+
+/*
+ * Authorize digest credentials
+ */
+static inline int authenticate(struct sip_msg* msg, str* realm,
+			       hdr_types_t hftype)
+{
+	int res;
+	auth_result_t ret;
+	struct hdr_field* h;
+	auth_body_t* cred;
+	str* uri;
+	struct sip_uri puri;
+	str user, did;
+	VALUE_PAIR* received;
+
+	cred = 0;
+	ret = -1;
+	user.s = 0;
+	received = NULL;
+
+	switch(auth_api.pre_auth(msg, realm, hftype, &h, NULL)) {
+	default:
+		BUG("unexpected reply '%d'.\n", auth_api.pre_auth(msg, realm, hftype,
+				&h, NULL));
+#ifdef EXTRA_DEBUG
+		abort();
+#endif
+	case ERROR:
+	case BAD_CREDENTIALS:
+	    ret = -3;
+	    goto end;
+
+	case NOT_AUTHENTICATED:
+	    ret = -1;
+	    goto end;
+
+	case DO_AUTHENTICATION:
+	    break;
+
+	case AUTHENTICATED:
+	    ret = 1;
+	    goto end;
+	}
+
+	cred = (auth_body_t*)h->parsed;
+
+	if (use_did) {
+	    if (msg->REQ_METHOD == METHOD_REGISTER) {
+			ret = get_to_did(&did, msg);
+	    } else {
+			ret = get_from_did(&did, msg);
+	    }
+	    if (ret == 0) {
+			did.s = DEFAULT_DID;
+			did.len = sizeof(DEFAULT_DID) - 1;
+	    }
+	} else {
+	    did.len = 0;
+	    did.s = 0;
+	}
+
+	if (get_uri(msg, &uri) < 0) {
+		LOG(L_ERR, "authorize(): From/To URI not found\n");
+		ret = -1;
+		goto end;
+	}
+	
+	if (parse_uri(uri->s, uri->len, &puri) < 0) {
+		LOG(L_ERR, "authorize(): Error while parsing From/To URI\n");
+		ret = -1;
+		goto end;
+	}
+
+	user.s = (char *)pkg_malloc(puri.user.len);
+	if (user.s == NULL) {
+		LOG(L_ERR, "authorize: No memory left\n");
+		ret = -1;
+		goto end;
+	}
+	un_escape(&(puri.user), &user);
+
+	res = radius_authorize_sterman(&received, msg, &cred->digest, &msg->first_line.u.request.method, &user);
+	if (res == 1) {
+	    switch(auth_api.post_auth(msg, h)) {
+	    case ERROR:             
+	    case BAD_CREDENTIALS:
+		ret = -2;
+		break;
+
+	    case NOT_AUTHENTICATED:
+		ret = -1;
+		break;
+
+	    case AUTHENTICATED:
+		if (generate_avps(received) < 0) {
+		    ret = -1;
+		    break;
+		}
+		ret = 1;
+		break;
+
+	    default:
+		ret = -1;
+		break;
+	    }
+	} else {
+	    ret = -1;
+	}
+
+ end:
+	if (received) rc_avpair_free(received);
+	if (user.s) pkg_free(user.s);
+	if (ret < 0) {
+	    if (auth_api.build_challenge(msg, (cred ? cred->stale : 0), realm, NULL, NULL, hftype) < 0) {
+		ERR("Error while creating challenge\n");
+		ret = -2;
+	    }
+	}
+	return ret;
+}
+
+
+/*
+ * Authorize using Proxy-Authorize header field
+ */
+int radius_proxy_authorize(struct sip_msg* _msg, char* p1, char* p2)
+{
+    str realm;
+
+    if (get_str_fparam(&realm, _msg, (fparam_t*)p1) < 0) {
+	ERR("Cannot obtain digest realm from parameter '%s'\n", ((fparam_t*)p1)->orig);
+	return -1;
+    }
+    
+	 /* realm parameter is converted to str* in str_fixup */
+    return authenticate(_msg, &realm, HDR_PROXYAUTH_T);
+}
+
+
+/*
+ * Authorize using WWW-Authorize header field
+ */
+int radius_www_authorize(struct sip_msg* _msg, char* p1, char* p2)
+{
+    str realm;
+
+    if (get_str_fparam(&realm, _msg, (fparam_t*)p1) < 0) {
+	ERR("Cannot obtain digest realm from parameter '%s'\n", ((fparam_t*)p1)->orig);
+	return -1;
+    }
+    
+    return authenticate(_msg, &realm, HDR_AUTHORIZATION_T);
+}
+

+ 52 - 0
modules_s/auth_radius/authorize.h

@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ * Digest Authentication - Radius support
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * -------
+ * 2003-03-09: Based on authorize.h from radius_auth (janakj)
+ */
+
+#ifndef AUTHORIZE_H
+#define AUTHORIZE_H
+
+#include "../../parser/msg_parser.h"
+
+
+/*
+ * Authorize using Proxy-Authorization header field
+ */
+int radius_proxy_authorize(struct sip_msg* _msg, char* _realm, char* _s2);
+
+
+/*
+ * Authorize using WWW-Authorization header field
+ */
+int radius_www_authorize(struct sip_msg* _msg, char* _realm, char* _s2);
+
+
+#endif /* AUTHORIZE_H */

+ 204 - 0
modules_s/auth_radius/authrad_mod.c

@@ -0,0 +1,204 @@
+/*
+ * $Id$
+ *
+ * Digest Authentication - Radius support
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * -------
+ *  2003-03-09: Based on auth_mod.c from radius_auth (janakj)
+ *  2003-03-11: New module interface (janakj)
+ *  2003-03-16: flags export parameter added (janakj)
+ *  2003-03-19  all mallocs/frees replaced w/ pkg_malloc/pkg_free (andrei)
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../../sr_module.h"
+#include "../../error.h"
+#include "../../dprint.h"
+#include "../../mem/mem.h"
+#include "../../config.h"
+#include "authrad_mod.h"
+#include "authorize.h"
+
+#ifdef RADIUSCLIENT_NG_4
+#  include <radiusclient.h>
+# else
+#  include <radiusclient-ng.h>
+#endif
+
+MODULE_VERSION
+
+struct attr attrs[A_MAX];
+struct val vals[V_MAX];
+void *rh;
+
+auth_api_t auth_api;
+
+static int mod_init(void);                        /* Module initialization function */
+
+int use_did = 1;
+int use_ruri_flag = -1;
+
+
+/*
+ * Module parameter variables
+ */
+static char* radius_config = "/usr/local/etc/radiusclient/radiusclient.conf";
+static int service_type = -1;
+
+
+/*
+ * Exported functions
+ */
+static cmd_export_t cmds[] = {
+	{"radius_www_authorize",      radius_www_authorize,   1, fixup_var_str_1, REQUEST_ROUTE},
+	{"radius_proxy_authorize",    radius_proxy_authorize, 1, fixup_var_str_1, REQUEST_ROUTE},
+	{"radius_www_authenticate",   radius_www_authorize,   1, fixup_var_str_1, REQUEST_ROUTE},
+	{"radius_proxy_authenticate", radius_proxy_authorize, 1, fixup_var_str_1, REQUEST_ROUTE},
+	{0, 0, 0, 0, 0}
+};
+
+
+/*
+ * Exported parameters
+ */
+static param_export_t params[] = {
+	{"radius_config",    PARAM_STRING, &radius_config },
+	{"service_type",     PARAM_INT,   &service_type   },
+	{"use_did",          PARAM_INT,   &use_did },
+	{"use_ruri_flag",    PARAM_INT,   &use_ruri_flag },
+	{0, 0, 0}
+};
+
+
+/*
+ * Module interface
+ */
+struct module_exports exports = {
+	"auth_radius",
+	cmds,       /* Exported functions */
+	0,          /* RPC methods */
+	params,     /* Exported parameters */
+	mod_init,   /* module initialization function */
+	0,          /* response function */
+	0,          /* destroy function */
+	0,          /* oncancel function */
+	0           /* child initialization function */
+};
+
+
+/*
+ * Module initialization function
+ */
+static int mod_init(void)
+{
+	DICT_VENDOR *vend;
+	bind_auth_t bind_auth;
+
+	DBG("auth_radius - Initializing\n");
+
+	memset(attrs, 0, sizeof(attrs));
+	memset(vals, 0, sizeof(vals));
+
+	     /* RFC2865, RFC2866 */
+	attrs[A_USER_NAME].n			= "User-Name";
+	attrs[A_SERVICE_TYPE].n			= "Service-Type";
+
+	     /* draft-sterman-aaa-sip-00 */
+	attrs[A_DIGEST_RESPONSE].n		= "Digest-Response";
+	attrs[A_DIGEST_REALM].n			= "Digest-Realm";
+	attrs[A_DIGEST_NONCE].n			= "Digest-Nonce";
+	attrs[A_DIGEST_METHOD].n		= "Digest-Method";
+	attrs[A_DIGEST_URI].n			= "Digest-URI";
+	attrs[A_DIGEST_QOP].n			= "Digest-QOP";
+	attrs[A_DIGEST_ALGORITHM].n		= "Digest-Algorithm";
+	attrs[A_DIGEST_BODY_DIGEST].n		= "Digest-Body-Digest";
+	attrs[A_DIGEST_CNONCE].n		= "Digest-CNonce";
+	attrs[A_DIGEST_NONCE_COUNT].n		= "Digest-Nonce-Count";
+	attrs[A_DIGEST_USER_NAME].n		= "Digest-User-Name";
+
+	     /* SER-specific */
+	attrs[A_SER_URI_USER].n			= "SER-Uri-User";
+	attrs[A_SER_ATTR].n	                = "SER-Attr";
+	attrs[A_SER_UID].n                      = "SER-UID";
+	attrs[A_SER_SERVICE_TYPE].n             = "SER-Service-Type";
+
+	     /* SER-Service-Type */
+	vals[V_DIGEST_AUTHENTICATION].n         = "Digest-Authentication";
+
+	attrs[A_CISCO_AVPAIR].n			= "Cisco-AVPair";
+
+	     /* draft-schulzrinne-sipping-radius-accounting-00 */
+	vals[V_SIP_SESSION].n			= "Sip-Session";
+
+
+	if ((rh = rc_read_config(radius_config)) == NULL) {
+		LOG(L_ERR, "auth_radius: Error opening configuration file \n");
+		return -1;
+	}
+
+	if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
+		LOG(L_ERR, "auth_radius: Error opening dictionary file \n");
+		return -2;
+	}
+
+	vend = rc_dict_findvend(rh, "Cisco");
+	if (vend == NULL) {
+		DBG("auth_radius: No `Cisco' vendor in Radius "
+			   "dictionary\n");
+		attrs[A_CISCO_AVPAIR].n = NULL;
+	}
+	
+	vend = rc_dict_findvend(rh, "iptelorg");
+	if (vend == NULL) {
+		ERR("RADIUS dictionary is missing required vendor 'iptelorg'\n");
+		return -1;
+	}
+
+
+        bind_auth = (bind_auth_t)find_export("bind_auth", 0, 0);
+        if (!bind_auth) {
+		LOG(L_ERR, "auth_radius: Unable to find bind_auth function\n");
+	        return -1;
+	}
+
+	if (bind_auth(&auth_api) < 0) {
+		LOG(L_ERR, "auth_radius: Cannot bind to auth module\n");
+		return -4;
+	}
+
+	INIT_AV(rh, attrs, vals, "auth_radius", -5, -6);
+
+	if (service_type != -1) {
+		vals[V_SIP_SESSION].v = service_type;
+	}
+
+	return 0;
+}
+

+ 50 - 0
modules_s/auth_radius/authrad_mod.h

@@ -0,0 +1,50 @@
+/*
+ * $Id$
+ *
+ * Digest Authentication - Radius support
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * -------
+ * 2003-03-09: Based on auth_mod.h from radius_authorize (janakj)
+ */
+
+
+#ifndef AUTHRAD_MOD_H
+#define AUTHRAD_MOD_H
+
+#include "../auth/api.h"
+#include "../../rad_dict.h"
+
+extern struct attr attrs[];
+extern struct val vals[];
+extern void *rh;
+
+extern int use_did;
+extern int use_ruri_flag;
+
+extern auth_api_t auth_api;
+
+#endif /* AUTHRAD_MOD_H */

+ 29 - 0
modules_s/auth_radius/doc/Makefile

@@ -0,0 +1,29 @@
+#
+# The list of documents to build (without extensions)
+#
+DOCUMENTS = auth_radius
+
+#
+# The root directory containing Makefile.doc
+#
+ROOT_DIR=../../..
+
+#
+# Validate docbook documents before generating output
+# (may be slow)
+#
+#VALIDATE=1
+
+#
+# You can override the stylesheet used to generate
+# xhtml documents here
+#
+#XHTML_XSL=$(ROOT_DIR)/doc/stylesheets/xhtml.xsl
+
+#
+# You can override the stylesheet used to generate
+# plain text documents here
+#
+#TXT_XSL=$(XHTML_XSL)
+
+include $(ROOT_DIR)/Makefile.doc

+ 80 - 0
modules_s/auth_radius/doc/auth_radius.xml

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="auth_radius" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<authorgroup>
+	    <author>
+		<firstname>Jan</firstname>
+		<surname>Janak</surname>
+		<affiliation><orgname>FhG Fokus</orgname></affiliation>
+		<email>[email protected]</email>
+	    </author>
+	    <author>
+		<firstname>Juha</firstname>
+		<surname>Heinanen</surname>
+		<affiliation><orgname>Song Networks</orgname></affiliation>
+		<email>[email protected]</email>
+	    </author>
+	    <author>
+		<firstname>Stelios</firstname>
+		<surname>Sidiroglou-Douskos</surname>
+	    </author>
+	</authorgroup>
+	<copyright>
+	    <year>2002</year>
+	    <year>2003</year>
+	    <holder>FhG FOKUS</holder>
+	</copyright>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Auth_radius Module</title>
+
+    <section id="auth_radius.overview">
+	<title>Overview</title>
+	<para>
+	    This module contains functions that are used to perform
+	    authentication using a Radius server. Basically the proxy will pass
+	    along the credentials to the radius server which will in turn send
+	    a reply containing result of the authentication. So basically the
+	    whole authentication is done in the Radius server. Before sending
+	    the request to the radius server we perform some sanity checks over
+	    the credentials to make sure that only well formed credentials will
+	    get to the server. We have implemented radius authentication
+	    according to draft-sterman-aaa-sip-00. This module requires
+	    radiusclient library version 0.5.0 or higher which is available
+	    from <ulink
+	    url='http://developer.berlios.de/projects/radiusclient-ng/'>
+	    http://developer.berlios.de/projects/radiusclient-ng/</ulink>.
+	</para>
+    </section>
+
+    <section id="auth_radius.dep">
+	<title>Dependencies</title>
+	<para>
+	    The module depends on the following modules (in the other words the listed modules
+	    must be loaded before this module):
+	    <itemizedlist>
+	    	<listitem>
+		    <formalpara>
+		        <title>auth</title>
+		        <para>
+			    Generic authentication functions.
+		        </para>
+		    </formalpara>
+		</listitem>
+	    </itemizedlist>
+	</para>
+    </section>
+
+    <xi:include href="params.xml"/>
+    <xi:include href="functions.xml"/>
+    
+</section>

+ 110 - 0
modules_s/auth_radius/doc/functions.xml

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="auth_radius.functions" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Functions</title>
+    
+    <section id="radius_www_authorize">
+	<title><function>radius_www_authorize(realm)</function></title>
+	<para>
+	    The function verifies credentials according to <ulink
+		url="http://www.ietf.org/rfc/rfc2617.txt">RFC2617</ulink>. If
+	    the credentials are verified successfully then the function
+	    will succeed and mark the credentials as authorized (marked
+	    credentials can be later used by some other functions). If the
+	    function was unable to verify the credentials for some reason
+	    then it will fail and the script should call
+	    <function>www_challenge</function> which will challenge the
+	    user again.
+	</para>
+	<para>
+	    This function will, in fact, perform sanity checks over the
+	    received credentials and then pass them along to the radius server
+	    which will verify the credentials and return whether they are valid
+	    or not.
+	</para>
+	<para>Meaning of the parameter is as follows:</para>
+	<itemizedlist>
+	    <listitem>
+		<para>
+		    <emphasis>realm</emphasis> - Realm is a opaque string that
+		    the user agent should present to the user so he can decide
+		    what username and password to use. Usually this is domain
+		    of the host the server is running on.
+		</para>
+		<para>
+		    If an empty string "" is used then the server will generate
+		    it from the request. In case of REGISTER requests To header
+		    field domain will be used (because this header field
+		    represents a user being registered), for all other messages
+		    From header field domain will be used.
+		</para>
+	    </listitem>
+	</itemizedlist>
+	<example>
+	    <title><function>radius_www_authorize</function> usage</title>
+	    <programlisting>
+...
+if (!radius_www_authorize("iptel.org")) {
+    www_challenge("iptel.org", "1");
+};
+...
+	    </programlisting>
+	</example>
+    </section>
+    
+    <section id="radius_proxy_authorize">
+	<title><function moreinfo="none">radius_proxy_authorize(realm)</function></title>
+	<para>
+	    The function verifies credentials according to <ulink
+		url="http://www.ietf.org/rfc/rfc2617.txt">RFC2617</ulink>. If
+	    the credentials are verified successfully then the function
+	    will succeed and mark the credentials as authorized (marked
+	    credentials can be later used by some other functions). If the
+	    function was unable to verify the credentials for some reason
+	    then it will fail and the script should call
+	    <function>proxy_challenge</function> which will challenge the
+	    user again.
+	</para>
+	<para>
+	    This function will, in fact, perform sanity checks over the
+	    received credentials and then pass them along to the radius server
+	    which will verify the credentials and return whether they are valid
+	    or not.
+	</para>
+	<para>Meaning of the parameter is as follows:</para>
+	<itemizedlist>
+	    <listitem>
+		<para><emphasis>realm</emphasis> - Realm is a opaque string
+		    that the user agent should present to the user so he can
+		    decide what username and password to use. Usually this is
+		    domain of the host the server is running on.
+		</para>
+		<para>
+		    If an empty string "" is used then the server will generate it
+		    from the request. From header field domain will be used as realm.
+		</para>
+	    </listitem>
+	</itemizedlist>
+	<example>
+	    <title>proxy_authorize usage</title>
+	    <programlisting>
+...
+if (!radius_proxy_authorize("")) {
+    proxy_challenge("", "1");  # Realm will be autogenerated
+};
+...
+	    </programlisting>
+	</example>
+    </section>
+</section>

+ 76 - 0
modules_s/auth_radius/doc/params.xml

@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="auth_radius.parameters" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Parameters</title>
+
+    <section id="auth_radius.radius_config">
+	<title><varname>radius_config</varname> (string)</title>
+	<para>
+	    This is the location of the configuration file of radius client
+	    libraries.
+	</para>
+	<para>
+	    Default value is "/usr/local/etc/radiusclient/radiusclient.conf".
+	</para>
+	<example>
+	    <title><varname>radius_config</varname> parameter usage</title>
+	    <programlisting>
+modparam("auth_radius", "radius_config", "/etc/radiusclient.conf")
+	    </programlisting>
+	</example>
+    </section>
+
+    <section id="auth_radius.service_type">
+	<title><varname>service_type</varname> (integer)</title>
+	<para>
+	    This is the value of the Service-Type radius attribute to be
+	    used. The default should be fine for most people. See your radius
+	    client include files for numbers to be put in this parameter if you
+	    need to change it.
+	</para>
+	<para>
+	    Default value is "15".
+	</para>
+	<example>
+	    <title><varname>service_type</varname> usage</title>
+	    <programlisting>
+modparam("auth_radius", "service_type", 15)
+	    </programlisting>
+	</example>
+    </section>
+
+    <section id="auth_radius.use_ruri_flag">
+	<title><varname>use_ruri_flag</varname> (integer)</title>
+	<para>
+	    When this parameter is set to the value other than "-1" and the
+	    request being authenticated has flag with matching number set
+	    via setflag() function, use Request URI instead of uri parameter
+	    value from the Authorization / Proxy-Authorization header field
+	    to perform RADIUS authentication.  This is intended to provide
+	    workaround for misbehaving NAT / routers / ALGs that alter request
+	    in the transit, breaking authentication.  At the time of this
+	    writing, certain versions of Linksys WRT54GL are known to do that.
+	</para>
+	<para>
+	    Default value is "-1".
+	</para>
+	<example>
+	    <title><varname>use_ruri_flag</varname> usage</title>
+	    <programlisting>
+modparam("auth_radius", "use_ruri_flag", 22)
+	    </programlisting>
+	</example>
+    </section>
+
+</section>

+ 283 - 0
modules_s/auth_radius/sterman.c

@@ -0,0 +1,283 @@
+/* 
+ * $Id$
+ *
+ * Digest Authentication - Radius support
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * -------
+ * 2003-03-09: Based on digest.c from radius_auth module (janakj)
+ */
+
+
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "../auth/api.h"
+#include "../../rad_dict.h"
+#include "../../usr_avp.h"
+#include "../../ut.h"
+#include "sterman.h"
+#include "authrad_mod.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static int add_cisco_vsa(VALUE_PAIR** send, struct sip_msg* msg)
+{
+	str callid;
+
+	if (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) == -1) {
+		LOG(L_ERR, "add_cisco_vsa: Cannot parse Call-ID header field\n");
+		return -1;
+	}
+
+	if (!msg->callid) {
+		LOG(L_ERR, "add_cisco_vsa: Call-ID header field not found\n");
+		return -1;
+	}
+
+	callid.len = msg->callid->body.len + 8;
+	callid.s = pkg_malloc(callid.len);
+	if (callid.s == NULL) {
+		LOG(L_ERR, "add_cisco_vsa: No memory left\n");
+		return -1;
+	}
+
+	memcpy(callid.s, "call-id=", 8);
+	memcpy(callid.s + 8, msg->callid->body.s, msg->callid->body.len);
+
+	if (rc_avpair_add(rh, send, ATTRID(attrs[A_CISCO_AVPAIR].v), callid.s,
+			  callid.len, VENDOR(attrs[A_CISCO_AVPAIR].v)) == 0) {
+		LOG(L_ERR, "add_cisco_vsa: Unable to add Cisco-AVPair attribute\n");
+		pkg_free(callid.s);
+		return -1;
+	}
+
+	pkg_free(callid.s);
+	return 0;
+}
+
+
+/*
+ * This function creates and submits radius authentication request as per
+ * draft-sterman-aaa-sip-00.txt.  In addition, _user parameter is included
+ * in the request as value of a SER specific attribute type SIP-URI-User,
+ * which can be be used as a check item in the request.  Service type of
+ * the request is Authenticate-Only.
+ */
+int radius_authorize_sterman(VALUE_PAIR** received, struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) 
+{
+	static char msg[4096];
+	VALUE_PAIR *send;
+	UINT4 service, ser_service_type;
+	str method, user, user_name;
+	str *ruri;
+	int i;
+	
+	send = 0;
+
+	if (!(_cred && _method && _user)) {
+		LOG(L_ERR, "radius_authorize_sterman(): Invalid parameter value\n");
+		return -1;
+	}
+
+	method = *_method;
+	user = *_user;
+	
+	/*
+	 * Add all the user digest parameters according to the qop defined.
+	 * Most devices tested only offer support for the simplest digest.
+	 */
+	if (_cred->username.domain.len) {
+	        if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), 
+				   _cred->username.whole.s, _cred->username.whole.len, 
+			           VENDOR(attrs[A_USER_NAME].v))) {
+			LOG(L_ERR, "radius_authorize_sterman(): Unable to add User-Name attribute\n");
+			goto err;
+		}
+	} else {
+		user_name.len = _cred->username.user.len + _cred->realm.len + 1;
+		user_name.s = pkg_malloc(user_name.len);
+		if (!user_name.s) {
+			LOG(L_ERR, "radius_authorize_sterman(): No memory left\n");
+			return -3;
+		}
+		memcpy(user_name.s, _cred->username.whole.s, _cred->username.whole.len);
+		user_name.s[_cred->username.whole.len] = '@';
+		memcpy(user_name.s + _cred->username.whole.len + 1, _cred->realm.s, _cred->realm.len);
+		if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), 
+				   user_name.s, user_name.len, 
+				   VENDOR(attrs[A_USER_NAME].v))) {
+			LOG(L_ERR, "sterman(): Unable to add User-Name attribute\n");
+			pkg_free(user_name.s);
+			goto err;
+		}
+		pkg_free(user_name.s);
+	}
+
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_USER_NAME].v), 
+			   _cred->username.whole.s, _cred->username.whole.len, 
+			   VENDOR(attrs[A_DIGEST_USER_NAME].v))) {
+		LOG(L_ERR, "sterman(): Unable to add Digest-User-Name attribute\n");
+		goto err;
+	}
+
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_REALM].v), 
+			   _cred->realm.s, _cred->realm.len, 
+			   VENDOR(attrs[A_DIGEST_REALM].v))) {
+		LOG(L_ERR, "sterman(): Unable to add Digest-Realm attribute\n");
+		goto err;
+	}
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_NONCE].v), 
+			   _cred->nonce.s, _cred->nonce.len, 
+			   VENDOR(attrs[A_DIGEST_NONCE].v))) {
+		LOG(L_ERR, "sterman(): Unable to add Digest-Nonce attribute\n");
+		goto err;
+	}
+	
+	if (use_ruri_flag < 0 || isflagset(_msg, use_ruri_flag) != 1) {
+		ruri = &_cred->uri;
+	} else {
+		ruri = GET_RURI(_msg);
+	}
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_URI].v), 
+			   ruri->s, ruri->len, 
+			   VENDOR(attrs[A_DIGEST_URI].v))) {
+		LOG(L_ERR, "sterman(): Unable to add Digest-URI attribute\n");
+		goto err;
+	}
+		
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_METHOD].v),
+			   method.s, method.len, 
+			   VENDOR(attrs[A_DIGEST_METHOD].v))) {
+	        LOG(L_ERR, "sterman(): Unable to add Digest-Method attribute\n");
+		goto err;
+	}
+	
+	/* 
+	 * Add the additional authentication fields according to the QOP.
+	 */
+	if (_cred->qop.qop_parsed == QOP_AUTH) {
+		if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_QOP].v), "auth", 4,
+				   VENDOR(attrs[A_DIGEST_QOP].v))) {
+			LOG(L_ERR, "sterman(): Unable to add Digest-QOP attribute\n");
+			goto err;
+		}
+		if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_NONCE_COUNT].v), 
+				   _cred->nc.s, _cred->nc.len,
+				   VENDOR(attrs[A_DIGEST_NONCE_COUNT].v))) {
+			LOG(L_ERR, "sterman(): Unable to add Digest-CNonce-Count attribute\n");
+			goto err;
+		}
+		if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_CNONCE].v), 
+				   _cred->cnonce.s, _cred->cnonce.len,
+				   VENDOR(attrs[A_DIGEST_CNONCE].v))) {
+			LOG(L_ERR, "sterman(): Unable to add Digest-CNonce attribute\n");
+			goto err;
+		}
+	} else if (_cred->qop.qop_parsed == QOP_AUTHINT) {
+	        if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_QOP].v), "auth-int", 8, 
+				   VENDOR(attrs[A_DIGEST_QOP].v))) {
+		        LOG(L_ERR, "sterman(): Unable to add Digest-QOP attribute\n");
+			goto err;
+		}
+		if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_NONCE_COUNT].v), 
+				   _cred->nc.s, _cred->nc.len, 
+				   VENDOR(attrs[A_DIGEST_NONCE_COUNT].v))) {
+			LOG(L_ERR, "sterman(): Unable to add Digest-Nonce-Count attribute\n");
+			goto err;
+		}
+		if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_CNONCE].v), 
+				   _cred->cnonce.s, _cred->cnonce.len, 
+				   VENDOR(attrs[A_DIGEST_CNONCE].v))) {
+			LOG(L_ERR, "sterman(): Unable to add Digest-CNonce attribute\n");
+			goto err;
+		}
+		if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_BODY_DIGEST].v), 
+				   _cred->opaque.s, _cred->opaque.len, 
+				   VENDOR(attrs[A_DIGEST_BODY_DIGEST].v))) {
+			LOG(L_ERR, "sterman(): Unable to add Digest-Body-Digest attribute\n");
+			goto err;
+		}
+		
+	} else  {
+		/* send nothing for qop == "" */
+	}
+
+	/* Add the response... What to calculate against... */
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_RESPONSE].v), 
+			   _cred->response.s, _cred->response.len, 
+			   VENDOR(attrs[A_DIGEST_RESPONSE].v))) {
+		LOG(L_ERR, "sterman(): Unable to add Digest-Response attribute\n");
+		goto err;
+	}
+
+	/* Indicate the service type, Authenticate only in our case */
+	service = vals[V_SIP_SESSION].v;
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SERVICE_TYPE].v), 
+			   &service, -1, 
+			   VENDOR(attrs[A_SERVICE_TYPE].v))) {
+	        LOG(L_ERR, "sterman(): Unable to add Service-Type attribute\n");
+		goto err;
+	}
+
+	/* Indicate the service type, Authenticate only in our case */
+	ser_service_type = vals[V_DIGEST_AUTHENTICATION].v;
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), 
+			   &ser_service_type, -1, 
+			   VENDOR(attrs[A_SER_SERVICE_TYPE].v))) {
+		LOG(L_ERR, "sterman(): Unable to add SER-Service-Type attribute\n");
+		goto err;
+	}
+
+	/* Add SIP URI as a check item */
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_URI_USER].v), 
+			   user.s, user.len, 
+			   VENDOR(attrs[A_SER_URI_USER].v))) {
+		LOG(L_ERR, "sterman(): Unable to add Sip-URI-User attribute\n");
+		goto err;
+	}
+
+	if (attrs[A_CISCO_AVPAIR].n != NULL) {
+		if (add_cisco_vsa(&send, _msg)) {
+			goto err;
+		}
+	}
+
+	/* Send request */
+	if ((i = rc_auth(rh, SIP_PORT, send, received, msg)) == OK_RC) {
+		DBG("radius_authorize_sterman(): Success\n");
+		rc_avpair_free(send);
+		send = 0;
+		return 1;
+	} else {
+		DBG("radius_authorize_sterman(): Failure\n");
+		goto err;
+	}
+
+ err:
+	if (send) rc_avpair_free(send);	
+	return -1;
+}

+ 56 - 0
modules_s/auth_radius/sterman.h

@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * Digest Authentication - Radius support
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * -------
+ * 2003-03-09: Based on auth_mod.h from radius_authorize (janakj)
+ */
+
+#ifndef STERMAN_H
+#define STERMAN_H
+
+#ifdef RADIUSCLIENT_NG_4
+#  include <radiusclient.h>
+#else
+#  include <radiusclient-ng.h>
+#endif
+
+#include "../../str.h"
+#include "../../parser/digest/digest_parser.h"
+
+
+/*
+ * This function creates and submits radius authentication request as per
+ * draft-sterman-aaa-sip-00.txt.  In addition, _user parameter is included
+ * in the request as value of a SER specific attribute type SIP-URI-User,
+ * which can be be used as a check item in the request.  Service type of
+ * the request is Authenticate-Only.
+ */
+int radius_authorize_sterman(VALUE_PAIR** received, struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user); 
+
+#endif /* STERMAN_H */

+ 18 - 0
modules_s/avp_radius/Makefile

@@ -0,0 +1,18 @@
+# $Id$
+#
+# avp_radius module Makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+include ../../Makefile.radius
+
+auto_gen=
+NAME=avp_radius.so
+
+
+
+DEFS+=-DSER_MOD_INTERFACE
+
+include ../../Makefile.modules

+ 115 - 0
modules_s/avp_radius/README

@@ -0,0 +1,115 @@
+
+avp_radius Module
+
+Juha Heinanen
+
+  Copyright @ 2004 Juha Heinanen
+     _________________________________________________________
+
+   Table of Contents
+   1. User's Guide
+
+        1.1. Overview
+        1.2. Dependencies
+        1.3. Exported Parameters
+
+              1.3.1. radius_config (string)
+              1.3.2. caller_service_type (string)
+              1.3.3. callee_service_type (string)
+
+        1.4. Exported Functions
+
+              1.4.1. avp_load_radius()
+
+   List of Examples
+   1-1. radius_config parameter usage
+   1-2. caller_service_type usage
+   1-3. callee_service_type usage
+   1-4. avp_load_radius usage
+     _________________________________________________________
+
+Chapter 1. User's Guide
+
+1.1. Overview
+
+  avp_radius module allows loading of user's attributes into AVPs from
+  Radius.  User's name and domain can be based on From URI, Request
+  URI, or authenticated credentials.
+
+  The module assumes that Radius returns the AVPs as values of reply
+  attribute SIP-AVP.  Its value must be a string of form "name:value" or
+  of form "name#value".  In the first case, value is interpreted as
+  a string and in the second case as an int (second case has not been
+  implemented yet).
+
+  The module prefixes each attribute name as returned from Radius by
+  string "caller_" or "callee_" depending if caller's or callee's
+  attributes are loaded.
+
+1.2. Dependencies
+
+  None.
+
+1.3. Exported Parameters
+
+1.3.1. radius_config (string)
+
+   This is the location of the configuration file of radius
+   client libraries.
+
+   Default value is
+   "/usr/local/etc/radiusclient/radiusclient.conf".
+
+   Example 1-1. radius_config parameter usage
+modparam("avp_radius", "radius_config", "/etc/radiusclient.conf")
+     _________________________________________________________
+
+1.3.2. caller_service_type (integer)
+
+   This is the value of the Service-Type radius attribute to be
+   used, when caller's attributes are loaded.
+
+   Default value is dictionary value of "SIP-Caller-AVPs" Service-Type.
+
+   Example 1-2. caller_service_type usage
+modparam("avp_radius", "caller_service_type", 18)
+     _________________________________________________________
+
+1.3.2. callee_service_type (integer)
+
+   This is the value of the Service-Type radius attribute to be
+   used, when callee's attributes are loaded.
+
+   Default value is dictionary value of "SIP-Callee-AVPs" Service-Type.
+
+   Example 1-3. callee_service_type usage
+modparam("avp_radius", "callee_service_type", 19)
+     _________________________________________________________
+
+1.4. Exported Functions
+
+1.4.1. avp_load_radius(user)
+  
+   The functions loads user's attributes from radius and stores them
+   into AVPs.  Parameter "user" is used to indicate, whose attributes
+   are loaded.  Possible values are "caller", "caller_from_ruri", 
+   "callee", and "digest".
+
+   In "caller" case, attributes belong to the user of the From URI, in
+   "callee" case, to the user of the Request URI, and, in "digest" case,
+   to the authenticated user.  
+
+   The "caller_from_uri" case loads attribute value pairs defined for
+   caller (default SER-Caller-AVPs), but uses the user in the Request
+   URI. This is useful for the case where a call has been forwarded
+   by callee (Request URI) and you need to look up whether callee
+   is allowed to forward the call to ex. PSTN or if the call should be
+   anonymous (i.e. not show info about who diverted the call).
+
+   AVP name returned from Radius is prefixed by string "caller_", if
+   avp_load_radius parameter is "caller" or "digest", and by "callee_",
+   if parameter is "callee".
+
+   Example 1-4. avp_load_radius usage
+avp_load_radius("callee");
+     _________________________________________________________

+ 413 - 0
modules_s/avp_radius/avp_radius.c

@@ -0,0 +1,413 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 Juha Heinanen <[email protected]>
+ * Copyright (C) 2004 FhG Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef RADIUSCLIENT_NG_4
+#  include <radiusclient.h>
+# else
+#  include <radiusclient-ng.h>
+#endif
+
+#include "../../rad_dict.h"
+#include "../../sr_module.h"
+#include "../../mem/mem.h"
+#include "../../parser/digest/digest_parser.h"
+#include "../../parser/digest/digest.h"
+#include "../../parser/parse_uri.h"
+#include "../../parser/parse_from.h"
+#include "../domain/domain.h"
+#include "../../usr_avp.h"
+#include "../../ut.h"
+#include "../../config.h"
+
+
+MODULE_VERSION
+
+
+static int mod_init(void);
+static int radius_load_attrs(struct sip_msg*, char*, char*);
+static int attrs_fixup(void**, int);
+
+static char *radius_config = "/usr/local/etc/radiusclient/radiusclient.conf";
+
+static void *rh;
+struct attr attrs[A_MAX];
+struct val vals[V_MAX];
+
+static domain_get_did_t dm_get_did = NULL;
+
+
+/*
+ * Exported functions
+ */
+static cmd_export_t cmds[] = {
+    {"radius_load_attrs", radius_load_attrs, 2, attrs_fixup, REQUEST_ROUTE | FAILURE_ROUTE},
+    {0, 0, 0, 0, 0}
+};
+
+
+/*
+ * Exported parameters
+ */
+static param_export_t params[] = {
+    {"radius_config", PARAM_STRING, &radius_config },
+    {0, 0, 0}
+};
+
+
+struct module_exports exports = {
+    "avp_radius",
+    cmds,      /* Exported commands */
+    0,         /* RPC methods */
+    params,    /* Exported parameters */
+    mod_init,  /* module initialization function */
+    0,         /* response function*/
+    0,         /* destroy function */
+    0,         /* oncancel function */
+    0          /* per-child init function */
+};
+
+
+static int mod_init(void)
+{
+    DICT_VENDOR *vend;
+    memset(attrs, 0, sizeof(attrs));
+    memset(vals, 0, sizeof(vals));
+    
+    attrs[A_USER_NAME].n        = "User-Name";
+    attrs[A_SER_SERVICE_TYPE].n = "SER-Service-Type";
+    attrs[A_SER_ATTR].n	        = "SER-Attr";
+    attrs[A_SER_DID].n          = "SER-DID";
+    attrs[A_SER_URI_SCHEME].n   = "SER-Uri-Scheme";
+    
+    vals[V_GET_URI_ATTRS].n  = "Get-URI-Attrs";
+    vals[V_GET_USER_ATTRS].n = "Get-User-Attrs";
+
+	 /* open log */
+    rc_openlog("ser");
+    
+	 /* read config */
+    if ((rh = rc_read_config(radius_config)) == NULL) {
+	LOG(L_ERR, "avp_radius: Error opening radius config file: %s\n",
+	    radius_config);
+	return -1;
+    }
+    
+	 /* read dictionary */
+    if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
+	LOG(L_ERR, "avp_radius: Error reading radius dictionary\n");
+	return -1;
+    }
+    
+    vend = rc_dict_findvend(rh, "iptelorg");
+    if (vend == NULL) {
+	ERR("RADIUS dictionary is missing required vendor 'iptelorg'\n");
+	return -1;
+    }
+
+    INIT_AV(rh, attrs, vals, "avp", -1, -1);
+    return 0;
+}
+
+
+static void attr_name_value(str* name, str* value, VALUE_PAIR* vp)
+{
+    int i;
+    
+    for (i = 0; i < vp->lvalue; i++) {
+	if (vp->strvalue[i] == ':' || vp->strvalue[i] == '=') {
+	    name->s = vp->strvalue;
+	    name->len = i;
+	    
+	    if (i == (vp->lvalue - 1)) {
+		value->s = (char*)0;
+		value->len = 0;
+	    } else {
+		value->s = vp->strvalue + i + 1;
+		value->len = vp->lvalue - i - 1;
+	    }
+	    return;
+	}
+    }
+
+    name->len = value->len = 0;
+    name->s = value->s = (char*)0;
+}
+
+
+/*
+ * Generate AVPs from the database result
+ */
+static int generate_avps(unsigned int flags, VALUE_PAIR* received)
+{
+    int_str name, val;
+    VALUE_PAIR *vp;
+    
+    vp = received;
+    while ((vp = rc_avpair_get(vp, ATTRID(attrs[A_SER_ATTR].v), VENDOR(attrs[A_SER_ATTR].v)))) {
+	attr_name_value(&name.s, &val.s, vp);
+	if (name.s.len == 0) {
+	    ERR("Missing attribute name\n");
+	    return -1;
+	}
+
+	if (add_avp(flags | AVP_NAME_STR | AVP_VAL_STR, name, val) < 0) {
+	    ERR("Unable to create a new SER attribute\n");
+	    return -1;
+	}
+	vp = vp->next;
+    }
+    
+    return 0;
+}
+
+
+static int load_user_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp)
+{
+    static char rad_msg[4096];
+    str uid;
+    UINT4 service;
+    VALUE_PAIR* send, *received;
+
+    send = NULL;
+    received = NULL;
+
+    if (get_str_fparam(&uid, msg, (fparam_t*)fp) < 0) {
+	ERR("Unable to get UID\n");
+	return -1;
+    }
+
+    service = vals[V_GET_USER_ATTRS].v;
+
+    if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), 
+		       uid.s, uid.len,
+		       VENDOR(attrs[A_USER_NAME].v))) {
+	ERR("Error while adding A_USER_NAME\n");
+	goto error;
+    }
+    
+    if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), 
+		       &vals[V_GET_USER_ATTRS].v, -1, 
+		       VENDOR(attrs[A_SER_SERVICE_TYPE].v))) {
+	ERR("Error adding A_SERVICE_TYPE\n");
+	goto error;
+    }
+
+
+    if (rc_auth(rh, 0, send, &received, rad_msg) != OK_RC) {
+	DBG("load_user_attrs: Failure\n");
+	goto error;
+    }
+
+    DBG("load_user_attrs: Success\n");
+    rc_avpair_free(send);
+
+    if (generate_avps(flags, received) < 0) {
+	rc_avpair_free(received);
+	goto error;
+    }
+
+    rc_avpair_free(received);
+    return 1;
+
+ error:
+    if (send) rc_avpair_free(send);
+    if (received) rc_avpair_free(send);
+    return -1;
+}
+
+
+static int load_uri_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp)
+{
+    static char rad_msg[4096];
+    struct sip_uri puri;
+    str uri, did, scheme;
+    UINT4 service;
+    VALUE_PAIR* send, *received;
+
+    send = NULL;
+    received = NULL;
+
+    if (get_str_fparam(&uri, msg, (fparam_t*)fp) != 0) {
+	ERR("Unable to get URI\n");
+	return -1;
+    }
+
+    if (parse_uri(uri.s, uri.len, &puri) < 0) {
+	ERR("Error while parsing URI '%.*s'\n", uri.len, uri.s);
+	return -1;
+    }
+
+    if (puri.host.len) {
+	/* domain name is present */
+	if (dm_get_did(&did, &puri.host) < 0) {
+		DBG("Cannot lookup DID for domain %.*s, using default value\n", puri.host.len, ZSW(puri.host.s));
+		did.s = DEFAULT_DID;
+		did.len = sizeof(DEFAULT_DID) - 1;
+	}
+    } else {
+	/* domain name is missing -- can be caused by tel: URI */
+	DBG("There is no domain name, using default value\n");
+	did.s = DEFAULT_DID;
+	did.len = sizeof(DEFAULT_DID) - 1;
+    }
+
+    uri_type_to_str(puri.type, &scheme);
+    service = vals[V_GET_URI_ATTRS].v;
+
+    if (scheme.len) {
+	if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_URI_SCHEME].v), 
+			   scheme.s, scheme.len,
+			   VENDOR(attrs[A_SER_URI_SCHEME].v))) {
+	    ERR("Error while adding A_SER_URI_SCHEME\n");
+	    goto error;
+	}
+    }
+
+    if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), 
+		       puri.user.s, puri.user.len,
+		       VENDOR(attrs[A_USER_NAME].v))) {
+	ERR("Error while adding A_USER_NAME\n");
+	goto error;
+    }
+
+    if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_DID].v), 
+		       did.s, did.len,
+		       VENDOR(attrs[A_SER_DID].v))) {
+	ERR("Error while adding A_SER_DID\n");
+	goto error;
+    }
+    
+    if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), 
+		       &vals[V_GET_URI_ATTRS].v, -1,
+		       VENDOR(attrs[A_SER_SERVICE_TYPE].v))) {
+	ERR("Error adding A_SERVICE_TYPE\n");
+	goto error;
+    }
+
+    if (rc_auth(rh, 0, send, &received, rad_msg) != OK_RC) {
+	DBG("load_uri_attrs: Failure\n");
+	goto error;
+    }
+
+    DBG("load_uri_attrs: Success\n");
+    rc_avpair_free(send);
+
+    if (generate_avps(flags, received) < 0) {
+	rc_avpair_free(received);
+	goto error;
+    }
+
+    rc_avpair_free(received);
+    return 1;
+
+ error:
+    if (send) rc_avpair_free(send);
+    if (received) rc_avpair_free(send);
+    return -1;
+}
+
+
+/*
+ * Load user attributes
+ */
+static int radius_load_attrs(struct sip_msg* msg, char* fl, char* fp)
+{
+    unsigned long flags;
+    
+    flags = (unsigned long)fl;
+
+    if (flags & AVP_CLASS_URI) {
+       	return load_uri_attrs(msg, flags, (fparam_t*)fp);
+    } else {
+	return load_user_attrs(msg, flags, (fparam_t*)fp);
+    }
+}
+
+
+static int attrs_fixup(void** param, int param_no)
+{
+    unsigned long flags;
+    char* s;
+    
+    if (param_no == 1) {
+	     /* Determine the track and class of attributes to be loaded */
+	s = (char*)*param;
+	flags = 0;
+	if (*s != '$' || (strlen(s) != 3)) {
+	    ERR("Invalid parameter value, $xy expected\n");
+	    return -1;
+	}
+	switch((s[1] << 8) + s[2]) {
+	case 0x4655: /* $fu */
+	case 0x6675:
+	case 0x4675:
+	case 0x6655:
+	    flags = AVP_TRACK_FROM | AVP_CLASS_USER;
+	    break;
+	    
+	case 0x4652: /* $fr */
+	case 0x6672:
+	case 0x4672:
+	case 0x6652:
+	    flags = AVP_TRACK_FROM | AVP_CLASS_URI;
+	    break;
+	    
+	case 0x5455: /* $tu */
+	case 0x7475:
+	case 0x5475:
+	case 0x7455:
+	    flags = AVP_TRACK_TO | AVP_CLASS_USER;
+	    break;
+	    
+	case 0x5452: /* $tr */
+	case 0x7472:
+	case 0x5472:
+	case 0x7452:
+	    flags = AVP_TRACK_TO | AVP_CLASS_URI;
+	    break;
+	    
+	default:
+	    ERR("Invalid parameter value: '%s'\n", s);
+	    return -1;
+	}
+
+	if ((flags & AVP_CLASS_URI) && !dm_get_did) {
+	    dm_get_did = (domain_get_did_t)find_export("get_did", 0, 0);
+	    if (!dm_get_did) {
+		ERR("Domain module required but not found\n");
+		return -1;
+	    }
+	}
+	
+	pkg_free(*param);
+	*param = (void*)flags;
+    } else if (param_no == 2) {
+	return fixup_var_str_12(param, 2);
+    }
+    return 0;
+}

+ 29 - 0
modules_s/avp_radius/doc/Makefile

@@ -0,0 +1,29 @@
+#
+# The list of documents to build (without extensions)
+#
+DOCUMENTS = avp_radius
+
+#
+# The root directory containing Makefile.doc
+#
+ROOT_DIR=../../..
+
+#
+# Validate docbook documents before generating output
+# (may be slow)
+#
+#VALIDATE=1
+
+#
+# You can override the stylesheet used to generate
+# xhtml documents here
+#
+#XHTML_XSL=$(ROOT_DIR)/doc/stylesheets/xhtml.xsl
+
+#
+# You can override the stylesheet used to generate
+# plain text documents here
+#
+#TXT_XSL=$(XHTML_XSL)
+
+include $(ROOT_DIR)/Makefile.doc

+ 53 - 0
modules_s/avp_radius/doc/avp_radius.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="avp_radius" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<authorgroup>
+	    <author>
+		<firstname>Juha</firstname>
+		<surname>Heinanen</surname>
+		<email>[email protected]</email>
+	    </author>
+	</authorgroup>
+	<copyright>
+	    <year>2004</year>
+	    <holder>Juha Heinanen</holder>
+	</copyright>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Avp_radius Module</title>
+
+    <section id="avp_radius.overview">
+	<title>Overview</title>
+	<para>
+	    avp_radius module allows loading of user's attributes into AVPs
+	    from Radius. User's name and domain can be based on From URI,
+	    Request URI, or authenticated credentials.
+	</para>
+	<para>
+	    The module assumes that Radius returns the AVPs as values of reply
+	    attribute SIP-AVP.  Its value must be a string of form "name:value"
+	    or of form "name#value".  In the first case, value is interpreted
+	    as a string and in the second case as an int (second case has not
+	    been implemented yet).
+	</para>
+	<para>
+	    The module prefixes each attribute name as returned from Radius by
+	    string "caller_" or "callee_" depending if caller's or callee's
+	    attributes are loaded.
+	</para>
+    </section>
+
+    <xi:include href="params.xml"/>
+    <xi:include href="functions.xml"/>
+
+</section>
+

+ 53 - 0
modules_s/avp_radius/doc/functions.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="avp_radius.functions" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Functions</title>
+
+    <section id="avp_load_radius">
+	<title><function>avp_load_radius(user)</function></title>
+	<para>
+	    The functions loads user's attributes from radius and stores them
+	    into AVPs.  Parameter "user" is used to indicate, whose attributes
+	    are loaded.  Possible values are "caller", "caller_from_ruri", 
+            "callee", and "digest".
+	</para>
+	<para>
+	    In "caller" case, attributes belong to the user of the From URI, in
+	    "callee" case, to the user of the Request URI, and, in "digest"
+	    case, to the authenticated user.
+	</para>
+        <para>
+            The "caller_from_uri" case loads attribute value pairs defined for
+            caller (default SER-Caller-AVPs), but uses the user in the Request
+            URI. This is useful for the case where a call has been forwarded
+            by callee (Request URI) and you need to look up whether callee
+            is allowed to forward the call to ex. PSTN or if the call should be
+            anonymous (i.e. not show info about who diverted the call).
+        </para>
+	<para>
+	    AVP name returned from Radius is prefixed by string "caller_", if
+	    avp_load_radius parameter is "caller" or "digest", and by
+	    "callee_", if parameter is "callee".
+	</para>
+	<example>
+	    <title><function>avp_load_radius</function> usage</title>
+	    <programlisting>
+...
+avp_load_radius("callee")
+...
+	    </programlisting>
+	</example>
+    </section>
+
+</section>

+ 52 - 0
modules_s/avp_radius/doc/params.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="avp_radius.parameters" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Parameters</title>
+
+    <section id="avp_radius.radius_config">
+	<title><varname>radius_config</varname> (string)</title>
+	<para>
+	    This is the location of the configuration file of radius client
+	    libraries.
+	</para>
+	<para>
+	    Default value is "/usr/local/etc/radiusclient/radiusclient.conf".
+	</para>
+	<example>
+	    <title>radius_config parameter usage</title>
+	    <programlisting>
+modparam("avp_radius", "radius_config", "/etc/radiusclient.conf")
+	    </programlisting>
+	</example>
+    </section>
+
+    <section id="caller_service_type">
+	<title><varname>caller_service_type</varname> (integer)</title>
+	<para>
+	    This is the value of the Service-Type radius attribute to be used,
+	    when caller's attributes are loaded.
+	</para>
+	<para>
+	    Default value is dictionary value of "SIP-Caller-AVPs"
+	    Service-Type.
+	</para>
+	<example>
+	    <title>radius_config parameter usage</title>
+	    <programlisting>
+modparam("avp_radius", "caller_service_type", 18)
+	    </programlisting>
+	</example>
+    </section>
+
+</section>

+ 16 - 0
modules_s/uri_radius/Makefile

@@ -0,0 +1,16 @@
+# $Id$
+#
+# URI checks using Radius
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+include ../../Makefile.radius
+
+auto_gen=
+NAME=uri_radius.so
+
+DEFS+=-DSER_MOD_INTERFACE
+
+include ../../Makefile.modules

+ 142 - 0
modules_s/uri_radius/README

@@ -0,0 +1,142 @@
+
+uri_radius Module
+
+Juha Heinanen
+
+   Song Networks
+
+Edited by
+
+Juha Heinanen
+
+   Copyright © 2003 Juha Heinanen
+     _________________________________________________________
+
+   Table of Contents
+   1. User's Guide
+
+        1.1. Overview
+        1.2. Dependencies
+
+              1.2.1. SER Modules
+              1.2.2. External Libraries or Applications
+
+        1.3. Exported Parameters
+
+              1.3.1. radius_config (string)
+              1.3.2. service_type (integer)
+
+        1.4. Exported Functions
+
+              1.4.1. radius_does_uri_exist()
+
+   2. Developer's Guide
+   3. Frequently Asked Questions
+
+   List of Examples
+   1-1. Set param_name parameter
+   1-2. Set param_name parameter
+   1-3. radius_does_uri_exist usage
+     _________________________________________________________
+
+Chapter 1. User's Guide
+
+1.1. Overview
+
+   URI check using Radius server.
+     _________________________________________________________
+
+1.2. Dependencies
+
+1.2.1. SER Modules
+
+   The following modules must be loaded before this module:
+
+     * No dependencies on other SER modules.
+     _________________________________________________________
+
+1.2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed
+   before running SER with this module loaded:
+
+     * radius client library.
+     _________________________________________________________
+
+1.3. Exported Parameters
+
+1.3.1. radius_config (string)
+
+   Radiusclient configuration file.
+
+   Default value is
+   "/usr/local/etc/radiusclient/radiusclient.conf". 
+
+   Example 1-1. Set param_name parameter
+...
+modparam("uri_radius", "radius_config", "/etc/radiusclient.conf")
+...
+     _________________________________________________________
+
+1.3.2. service_type (integer)
+
+   Radius service type used in radius_does_uri_exist check.
+
+   Default value is 10 (Call-Check). 
+
+   Example 1-2. Set param_name parameter
+...
+modparam("uri_radius", "service_type", 11)
+...
+     _________________________________________________________
+
+1.4. Exported Functions
+
+1.4.1. radius_does_uri_exist()
+
+   Checks from Radius if user@host in Request-URI is a local user. Can
+   be used to decide if 404 or 480 should be returned after lookup has
+   failed.  Adds SIP-AVP reply items, that must have a string value of
+   form "name:value", as AVPs.
+
+   Example 1-3. radius_does_uri_exist usage
+...
+if (radius_does_uri_exist()) {
+    ...
+};
+...
+     _________________________________________________________
+
+Chapter 2. Developer's Guide
+
+   The module does not provide any sort of API to use in other
+   SER modules.
+     _________________________________________________________
+
+Chapter 3. Frequently Asked Questions
+
+   3.1. Where can I find more about SER?
+   3.2. Where can I post a question about this module?
+   3.3. How can I report a bug?
+
+   3.1. Where can I find more about SER?
+
+   Take a look at http://iptel.org/ser.
+
+   3.2. Where can I post a question about this module?
+
+   First at all check if your question was already answered on
+   one of our mailing lists:
+
+     * http://mail.iptel.org/mailman/listinfo/serusers
+     * http://mail.iptel.org/mailman/listinfo/serdev
+
+   E-mails regarding any stable version should be sent to
+   <[email protected]> and e-mail regarding development versions
+   or CVS snapshots should be send to <[email protected]>.
+
+
+   3.3. How can I report a bug?
+
+   Please follow the guidelines provided at:
+   http://iptel.org/ser/bugs

+ 168 - 0
modules_s/uri_radius/checks.c

@@ -0,0 +1,168 @@
+/* checks.c v 0.1 2003/1/20
+ *
+ * Radius based checks
+ *
+ * Copyright (C) 2002-2003 Juha Heinanen
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * -------
+ * 2003-03-11: Code cleanup (janakj)
+ */
+
+
+#include <string.h>
+#include "../../mem/mem.h"
+#include "../../parser/parse_uri.h"
+#include "../../dprint.h"
+#include "../../usr_avp.h"
+#include "../../ut.h"
+#include "../../rad_dict.h"
+#include "checks.h"
+#include "urirad_mod.h"
+
+#ifdef RADIUSCLIENT_NG_4
+#  include <radiusclient.h>
+#else
+#  include <radiusclient-ng.h>
+#endif
+
+
+/*
+ * Split name:value into string name and string value
+ */
+static void attr_name_value(VALUE_PAIR* vp, str* name, str* value)
+{
+	int i;
+	
+	for (i = 0; i < vp->lvalue; i++) {
+		if (vp->strvalue[i] == ':') {
+			name->s = vp->strvalue;
+			name->len = i;
+
+			if (i == (vp->lvalue - 1)) {
+				value->s = (char*)0;
+				value->len = 0;
+			} else {
+				value->s = vp->strvalue + i + 1;
+				value->len = vp->lvalue - i - 1;
+			}
+			return;
+		}
+	}
+
+	name->len = value->len = 0;
+	name->s = value->s = (char*)0;
+}
+
+
+/*
+ * Generate AVPs from the database result
+ */
+static int generate_avps(VALUE_PAIR* received)
+{
+	int_str name, val;
+	VALUE_PAIR *vp;
+
+	vp = received;
+
+	while ((vp = rc_avpair_get(vp, attrs[A_SER_ATTR].v, 0))) {
+		attr_name_value(vp, &name.s, &val.s);
+		
+		if (add_avp(AVP_NAME_STR | AVP_VAL_STR, name, val) < 0) {
+			LOG(L_ERR, "generate_avps: Unable to create a new AVP\n");
+		} else {
+			DBG("generate_avps: AVP '%.*s'='%.*s' has been added\n",
+			    name.s.len, ZSW(name.s.s), 
+			    val.s.len, ZSW(val.s.s));
+		}
+		vp = vp->next;
+	}
+	
+	return 0;
+}
+
+
+/*
+ * Check from Radius if request URI belongs to a local user.
+ * User-Name is user@host of request Uri and Service-Type is Call-Check.
+ */
+int radius_does_uri_exist(struct sip_msg* _m, char* _s1, char* _s2)
+{
+	static char msg[4096];
+	VALUE_PAIR *send, *received;
+	UINT4 service;
+	char* at, *uri;
+
+	send = received = 0;
+
+	if (parse_sip_msg_uri(_m) < 0) {
+		LOG(L_ERR, "radius_does_uri_exist(): Error while parsing URI\n");
+		return -1;
+	}
+	
+	uri = (char*)pkg_malloc(_m->parsed_uri.user.len + _m->parsed_uri.host.len + 2);
+	if (!uri) {
+		LOG(L_ERR, "radius_does_uri_exist(): No memory left\n");
+		return -2;
+	}
+
+	at = uri;
+	memcpy(at, _m->parsed_uri.user.s, _m->parsed_uri.user.len);
+	at += _m->parsed_uri.user.len;
+	*at = '@';
+	at++;
+	memcpy(at , _m->parsed_uri.host.s, _m->parsed_uri.host.len);
+	at += _m->parsed_uri.host.len;
+	*at = '\0';
+
+	if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, uri, -1, 0)) {
+		LOG(L_ERR, "radius_does_uri_exist(): Error adding User-Name\n");
+		rc_avpair_free(send);
+		pkg_free(uri);
+	 	return -3;
+	}
+
+	service = vals[V_CALL_CHECK].v;
+	if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) {
+		LOG(L_ERR, "radius_does_uri_exist(): Error adding service type\n");
+		rc_avpair_free(send);
+		pkg_free(uri);
+	 	return -4;  	
+	}
+	
+	if (rc_auth(rh, 0, send, &received, msg) == OK_RC) {
+		DBG("radius_does_uri_exist(): Success\n");
+		rc_avpair_free(send);
+		generate_avps(received);
+		rc_avpair_free(received);
+		pkg_free(uri);
+		return 1;
+	} else {
+		DBG("radius_does_uri_exist(): Failure\n");
+		rc_avpair_free(send);
+		rc_avpair_free(received);
+		pkg_free(uri);
+		return -5;
+	}
+}

+ 43 - 0
modules_s/uri_radius/checks.h

@@ -0,0 +1,43 @@
+/* domain.h v 0.1 2003/1/20
+ *
+ * Header file for radius based checks
+ *
+ * Copyright (C) 2002-2003 Juha Heinanen
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef CHECKS_H
+#define CHECKS_H
+
+
+#include "../../parser/msg_parser.h"
+
+
+/*
+ * Check from radius if Request URI exists
+ */
+int radius_does_uri_exist(struct sip_msg* _msg,  char* _str1, char* _str2);
+
+
+#endif /* CHECKS_H */

+ 29 - 0
modules_s/uri_radius/doc/Makefile

@@ -0,0 +1,29 @@
+#
+# The list of documents to build (without extensions)
+#
+DOCUMENTS = uri_radius
+
+#
+# The root directory containing Makefile.doc
+#
+ROOT_DIR=../../..
+
+#
+# Validate docbook documents before generating output
+# (may be slow)
+#
+#VALIDATE=1
+
+#
+# You can override the stylesheet used to generate
+# xhtml documents here
+#
+#XHTML_XSL=$(ROOT_DIR)/doc/stylesheets/xhtml.xsl
+
+#
+# You can override the stylesheet used to generate
+# plain text documents here
+#
+#TXT_XSL=$(XHTML_XSL)
+
+include $(ROOT_DIR)/Makefile.doc

+ 38 - 0
modules_s/uri_radius/doc/functions.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="uri_radius.functions" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Functions</title>
+
+    <section id="radius_does_uri_exist">
+	<title>
+	    <function>radius_does_uri_exist()</function>
+	</title>
+	<para>
+	    Checks from Radius if user@host in Request-URI is a local
+	    user. Can be used to decide if 404 or 480 should be returned after
+	    lookup has failed.  Adds SIP-AVP reply items, that must have a
+	    string value of form "name:value", as AVPs.
+	</para>
+	<example>
+	    <title><function>radius_does_uri_exist</function> usage</title>
+	    <programlisting>
+...
+if (radius_does_uri_exist()) {
+    ...
+};
+...
+	    </programlisting>
+	</example>
+    </section>
+</section>

+ 53 - 0
modules_s/uri_radius/doc/params.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="uri_radius.parameters" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Parameters</title>
+
+    <section id="uri_radius.radius_config">
+	<title><varname>radius_config</varname> (string)</title>
+	<para>
+	    Radiusclient configuration file.
+	</para>
+	<para>
+	    Default value is "/usr/local/etc/radiusclient/radiusclient.conf".
+	</para>
+	<example>
+	    <title>Set <varname>param_name</varname> parameter</title>
+	    <programlisting>
+...
+modparam("uri_radius", "radius_config", "/etc/radiusclient.conf")
+...
+	    </programlisting>
+	</example>
+    </section>
+
+    <section id="uri_radius.service_type">
+	<title><varname>service_type</varname> (integer)</title>
+	<para>
+	    Radius service type used in <function>radius_does_uri_exist check</function>.
+	</para>
+	<para>
+	    Default value is 10 (Call-Check).
+	</para>
+	<example>
+	    <title>Set <varname>param_name</varname> parameter</title>
+	    <programlisting>
+...
+modparam("uri_radius", "service_type", 11)
+...
+	    </programlisting>
+	</example>
+    </section>
+
+</section>

+ 57 - 0
modules_s/uri_radius/doc/uri_radius.xml

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="uri_radius" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<authorgroup>
+	    <author>
+		<firstname>Juha</firstname>
+		<surname>Heinanen</surname>
+		<affiliation><orgname>Song Networks</orgname></affiliation>
+		<address>
+		    <email>[email protected]</email>
+		</address>
+	    </author>
+	</authorgroup>
+	<copyright>
+	    <year>2003</year>
+	    <holder>Juha Heinanen</holder>
+	</copyright>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Uri_radius Module</title>
+
+    <section id="uri_radius.overview">
+	<title>Overview</title>
+	<para>URI check using Radius server.</para>
+    </section>
+    
+    <section id="uri_radius.dep">
+	<title>Dependencies</title>
+	<para>
+	    The following libraries or applications must be installed before
+	    running SER with this module loaded:
+	    <itemizedlist>
+		<listitem>
+		    <para>
+			radius client library.
+		    </para>
+		</listitem>
+	    </itemizedlist>
+	</para>
+    </section>
+
+    <xi:include href="params.xml"/>
+    <xi:include href="functions.xml"/>
+
+</section>
+
+
+

+ 126 - 0
modules_s/uri_radius/urirad_mod.c

@@ -0,0 +1,126 @@
+/*
+ * $Id$
+ *
+ * URI checks using Radius
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ * 2003-03-15 - created by janakj
+ * 2003-03-16 - flags export parameter added (janakj)
+ */
+
+#include "../../dprint.h"
+#include "../../sr_module.h"
+#include "urirad_mod.h"
+#include "checks.h"
+#include "../../rad_dict.h"
+
+#ifdef RADIUSCLIENT_NG_4
+#  include <radiusclient.h>
+#else
+#  include <radiusclient-ng.h>
+#endif
+
+MODULE_VERSION
+
+struct attr attrs[A_MAX];
+struct val vals[V_MAX];
+void *rh;
+
+static int mod_init(void); /* Module initialization function */
+
+
+/*
+ * Module parameter variables
+ */
+static char* radius_config = "/usr/local/etc/radiusclient/radiusclient.conf";
+static int service_type = -1;
+
+/*
+ * Exported functions
+ */
+static cmd_export_t cmds[] = {
+	{"radius_does_uri_exist", radius_does_uri_exist, 0, 0, REQUEST_ROUTE},
+	{0, 0, 0, 0, 0}
+};
+
+
+/*
+ * Exported parameters
+ */
+static param_export_t params[] = {
+	{"radius_config", PARAM_STRING, &radius_config},
+	{"service_type",  PARAM_INT,    &service_type},
+	{0, 0, 0}
+};
+
+
+/*
+ * Module interface
+ */
+struct module_exports exports = {
+	"uri_radius",
+	cmds,       /* Exported functions */
+	0,          /* RPC methods */
+	params,     /* Exported parameters */
+	mod_init,   /* module initialization function */
+	0,          /* response function */
+	0,          /* destroy function */
+	0,          /* oncancel function */
+	0           /* child initialization function */
+};
+
+
+static int mod_init(void)
+{
+	DBG("uri_radius - initializing\n");
+
+	memset(attrs, 0, sizeof(attrs));
+	memset(vals, 0, sizeof(vals));
+
+	attrs[A_USER_NAME].n	= "User-Name";
+	attrs[A_SERVICE_TYPE].n	= "Service-Type";
+
+	attrs[A_SER_ATTR].n	= "SER-Attrs";
+	vals[V_CALL_CHECK].n = "Call-Check";
+
+	if ((rh = rc_read_config(radius_config)) == NULL) {
+		LOG(L_ERR, "uri_radius: Error opening configuration file \n");
+		return -1;
+	}
+
+	if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
+		LOG(L_ERR, "uri_radius: Error opening dictionary file \n");
+		return -2;
+	}
+
+	INIT_AV(rh, attrs, vals, "uri_radius", -3, -4);
+
+	if (service_type != -1)
+		vals[V_CALL_CHECK].v = service_type;
+
+	return 0;
+}

+ 43 - 0
modules_s/uri_radius/urirad_mod.h

@@ -0,0 +1,43 @@
+/*
+ * $Id$
+ *
+ * URI checks using Radius
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ * 2003-03-15 - Created by janakj
+ */
+
+#ifndef URIRAD_MOD_H
+#define URIRAD_MOD_H
+
+#include "../../rad_dict.h" /* attr & val */
+
+extern struct attr attrs[];
+extern struct val vals[];
+extern void *rh;
+
+#endif /* URIRAD_MOD_H */