From ade786a0f1f27ed486e1ea887f95174f7c55dd70 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 28 Mar 2016 20:25:50 +0200 Subject: [PATCH] radius: replace experimental Group-Name with Class attribute The current format allows to handle multiple groups and is used by several radius servers. Suggested by Yick Xie. --- doc/README-radius.md | 15 ++++-------- src/auth/radius.c | 55 +++++++++++++++++++++++++++++++++++++------- src/auth/radius.h | 4 +++- src/str.c | 14 +++++++++++ src/str.h | 2 ++ 5 files changed, 71 insertions(+), 19 deletions(-) diff --git a/doc/README-radius.md b/doc/README-radius.md index a3502df4..35eba62a 100644 --- a/doc/README-radius.md +++ b/doc/README-radius.md @@ -82,6 +82,11 @@ ATTRIBUTE Framed-IP-Netmask 9 ipaddr # a CIDR string) ATTRIBUTE Framed-Route 22 string +# Sets group name using format "OU=group1;group2" +# Note that the groups sent by the server must be made known +# to ocserv, via the select-group variable. +ATTRIBUTE Class 25 string + # sets DNS servers VENDOR Microsoft 311 @@ -112,14 +117,4 @@ ATTRIBUTE DNS-Server-IPv6-Address 169 ipv6addr # Sets IPv6 routes ATTRIBUTE Framed-IPv6-Prefix 97 ipv6prefix ATTRIBUTE Route-IPv6-Information 170 ipv6prefix - - - -############################ -# Experimental attributes # -############################ - -# Experimental Non Protocol Attributes used by Cistron-Radiusd -# -ATTRIBUTE Group-Name 1030 string ``` diff --git a/src/auth/radius.c b/src/auth/radius.c index a5995ac7..dae4949f 100644 --- a/src/auth/radius.c +++ b/src/auth/radius.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014 Red Hat, Inc. + * Copyright (C) 2014-2016 Red Hat, Inc. + * Copyright (C) 2016 Nikos Mavrogiannopoulos * * This file is part of ocserv. * @@ -28,6 +29,7 @@ #include /* inet_ntop */ #include "radius.h" #include "auth/common.h" +#include "str.h" #ifdef HAVE_RADIUS @@ -39,7 +41,7 @@ # include #endif -#define RAD_GROUP_NAME 1030 +#define RAD_GROUP_NAME PW_CLASS #define RAD_IPV4_DNS1 ((311<<16)|(28)) #define RAD_IPV4_DNS2 ((311<<16)|(29)) @@ -134,13 +136,16 @@ static int radius_auth_init(void **ctx, void *pool, const common_auth_init_st *i static int radius_auth_group(void *ctx, const char *suggested, char *groupname, int groupname_size) { struct radius_ctx_st *pctx = ctx; + unsigned i; groupname[0] = 0; if (suggested != NULL) { - if (strcmp(suggested, pctx->groupname) == 0) { - strlcpy(groupname, pctx->groupname, groupname_size); - return 0; + for (i=0;igroupnames_size;i++) { + if (strcmp(suggested, pctx->groupnames[i]) == 0) { + strlcpy(groupname, pctx->groupnames[i], groupname_size); + return 0; + } } syslog(LOG_AUTH, @@ -149,9 +154,10 @@ static int radius_auth_group(void *ctx, const char *suggested, char *groupname, return -1; } - if (pctx->groupname[0] != 0 && groupname[0] == 0) { - strlcpy(groupname, pctx->groupname, groupname_size); + if (pctx->groupnames_size > 0 && groupname[0] == 0) { + strlcpy(groupname, pctx->groupnames[0], groupname_size); } + return 0; } @@ -190,6 +196,39 @@ static void append_route(struct radius_ctx_st *pctx, const char *route, unsigned } } +/* Parses group of format "OU=group1;group2;group3" */ +static void parse_groupnames(struct radius_ctx_st *pctx, const char *full) +{ + char *p, *p2; + unsigned i; + + pctx->groupnames_size = 0; + + if (strncmp(full, "OU=", 3) == 0) { + full += 3; + + p = talloc_strdup(pctx, full); + if (p == NULL) + return; + + i = 0; + p2 = strsep(&p, ";"); + while(p2 != NULL) { + pctx->groupnames[i++] = p2; + pctx->groupnames_size = i; + + trim_trailing_whitespace(p2); + + p2 = strsep(&p, ";"); + } + } else { + pctx->groupnames[0] = talloc_strdup(pctx, full); + if (pctx->groupnames[0] == NULL) + return; + pctx->groupnames_size = 1; + } +} + /* Returns 0 if the user is successfully authenticated, and sets the appropriate group name. */ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len) @@ -290,7 +329,7 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len) goto fail; } else if (vp->attribute == RAD_GROUP_NAME && vp->type == PW_TYPE_STRING) { /* Group-Name */ - strlcpy(pctx->groupname, vp->strvalue, sizeof(pctx->groupname)); + parse_groupnames(pctx, vp->strvalue); } else if (vp->attribute == PW_FRAMED_IPV6_ADDRESS && vp->type == PW_TYPE_IPV6ADDR) { /* Framed-IPv6-Address */ if (inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6, sizeof(pctx->ipv6)) != NULL) { diff --git a/src/auth/radius.h b/src/auth/radius.h index 0489bd55..51dcc2f4 100644 --- a/src/auth/radius.h +++ b/src/auth/radius.h @@ -25,9 +25,11 @@ struct radius_ctx_st { char username[MAX_USERNAME_SIZE*2]; - char groupname[MAX_GROUPNAME_SIZE]; char user_agent[MAX_AGENT_NAME]; + char *groupnames[MAX_GROUPS]; + unsigned groupnames_size; + char remote_ip[MAX_IP_STR]; char our_ip[MAX_IP_STR]; unsigned interim_interval_secs; diff --git a/src/str.c b/src/str.c index 1303ddf0..1f51d5fe 100644 --- a/src/str.c +++ b/src/str.c @@ -30,6 +30,20 @@ #include #include "vasprintf.h" +void trim_trailing_whitespace(char *str) +{ + unsigned len = strlen(str); + char *p; + + if (len > 0) { + p = str+len-1; + while (c_isspace(*p) && p >= str) { + *p = 0; + p--; + } + } +} + #define MEMSUB(x,y) ((ssize_t)((ptrdiff_t)x-(ptrdiff_t)y)) void str_clear(str_st * str) diff --git a/src/str.h b/src/str.h index 7513e20f..782fa992 100644 --- a/src/str.h +++ b/src/str.h @@ -77,6 +77,8 @@ inline static void str_reset(str_st * buf) buf->length = 0; } +void trim_trailing_whitespace(char *str); + int str_append_printf(str_st *dest, const char *fmt, ...); int str_append_str(str_st *, const char *str); int str_replace_str(str_st *, const str_rep_tab *tab);