2006-08-04 03:48:59 +04:00
/*
* NetLabel CIPSO / IPv4 Support
*
* This file defines the CIPSO / IPv4 functions for the NetLabel system . The
* NetLabel system manages static and dynamic label mappings for network
* protocols such as CIPSO and RIPSO .
*
* Author : Paul Moore < paul . moore @ hp . com >
*
*/
/*
* ( c ) Copyright Hewlett - Packard Development Company , L . P . , 2006
*
* This program 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 .
*
* This program 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
*
*/
# include <linux/types.h>
# include <linux/socket.h>
# include <linux/string.h>
# include <linux/skbuff.h>
2006-09-29 01:51:47 +04:00
# include <linux/audit.h>
2006-08-04 03:48:59 +04:00
# include <net/sock.h>
# include <net/netlink.h>
# include <net/genetlink.h>
# include <net/netlabel.h>
# include <net/cipso_ipv4.h>
# include "netlabel_user.h"
# include "netlabel_cipso_v4.h"
2007-07-18 20:28:45 +04:00
# include "netlabel_mgmt.h"
2006-08-04 03:48:59 +04:00
2006-09-26 02:56:37 +04:00
/* Argument struct for cipso_v4_doi_walk() */
struct netlbl_cipsov4_doiwalk_arg {
struct netlink_callback * nl_cb ;
struct sk_buff * skb ;
u32 seq ;
} ;
2006-08-04 03:48:59 +04:00
/* NetLabel Generic NETLINK CIPSOv4 family */
static struct genl_family netlbl_cipsov4_gnl_family = {
. id = GENL_ID_GENERATE ,
. hdrsize = 0 ,
. name = NETLBL_NLTYPE_CIPSOV4_NAME ,
. version = NETLBL_PROTO_VERSION ,
2006-09-26 02:56:37 +04:00
. maxattr = NLBL_CIPSOV4_A_MAX ,
2006-08-04 03:48:59 +04:00
} ;
2006-09-26 02:56:37 +04:00
/* NetLabel Netlink attribute policy */
2007-06-05 23:38:30 +04:00
static const struct nla_policy netlbl_cipsov4_genl_policy [ NLBL_CIPSOV4_A_MAX + 1 ] = {
2006-09-26 02:56:37 +04:00
[ NLBL_CIPSOV4_A_DOI ] = { . type = NLA_U32 } ,
[ NLBL_CIPSOV4_A_MTYPE ] = { . type = NLA_U32 } ,
[ NLBL_CIPSOV4_A_TAG ] = { . type = NLA_U8 } ,
[ NLBL_CIPSOV4_A_TAGLST ] = { . type = NLA_NESTED } ,
[ NLBL_CIPSOV4_A_MLSLVLLOC ] = { . type = NLA_U32 } ,
[ NLBL_CIPSOV4_A_MLSLVLREM ] = { . type = NLA_U32 } ,
[ NLBL_CIPSOV4_A_MLSLVL ] = { . type = NLA_NESTED } ,
[ NLBL_CIPSOV4_A_MLSLVLLST ] = { . type = NLA_NESTED } ,
[ NLBL_CIPSOV4_A_MLSCATLOC ] = { . type = NLA_U32 } ,
[ NLBL_CIPSOV4_A_MLSCATREM ] = { . type = NLA_U32 } ,
[ NLBL_CIPSOV4_A_MLSCAT ] = { . type = NLA_NESTED } ,
[ NLBL_CIPSOV4_A_MLSCATLST ] = { . type = NLA_NESTED } ,
} ;
2006-08-04 03:48:59 +04:00
/*
* Helper Functions
*/
/**
* netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
* @ entry : the entry ' s RCU field
*
* Description :
* This function is designed to be used as a callback to the call_rcu ( )
* function so that the memory allocated to the DOI definition can be released
* safely .
*
*/
static void netlbl_cipsov4_doi_free ( struct rcu_head * entry )
{
struct cipso_v4_doi * ptr ;
ptr = container_of ( entry , struct cipso_v4_doi , rcu ) ;
switch ( ptr - > type ) {
case CIPSO_V4_MAP_STD :
kfree ( ptr - > map . std - > lvl . cipso ) ;
kfree ( ptr - > map . std - > lvl . local ) ;
kfree ( ptr - > map . std - > cat . cipso ) ;
kfree ( ptr - > map . std - > cat . local ) ;
break ;
}
kfree ( ptr ) ;
}
2006-09-26 02:56:37 +04:00
/**
* netlbl_cipsov4_add_common - Parse the common sections of a ADD message
* @ info : the Generic NETLINK info block
* @ doi_def : the CIPSO V4 DOI definition
*
* Description :
* Parse the common sections of a ADD message and fill in the related values
* in @ doi_def . Returns zero on success , negative values on failure .
*
*/
static int netlbl_cipsov4_add_common ( struct genl_info * info ,
struct cipso_v4_doi * doi_def )
{
struct nlattr * nla ;
int nla_rem ;
u32 iter = 0 ;
doi_def - > doi = nla_get_u32 ( info - > attrs [ NLBL_CIPSOV4_A_DOI ] ) ;
if ( nla_validate_nested ( info - > attrs [ NLBL_CIPSOV4_A_TAGLST ] ,
NLBL_CIPSOV4_A_MAX ,
netlbl_cipsov4_genl_policy ) ! = 0 )
return - EINVAL ;
nla_for_each_nested ( nla , info - > attrs [ NLBL_CIPSOV4_A_TAGLST ] , nla_rem )
if ( nla - > nla_type = = NLBL_CIPSOV4_A_TAG ) {
2007-01-05 23:08:22 +03:00
if ( iter > = CIPSO_V4_TAG_MAXCNT )
2006-09-26 02:56:37 +04:00
return - EINVAL ;
doi_def - > tags [ iter + + ] = nla_get_u8 ( nla ) ;
}
2007-01-05 23:08:22 +03:00
while ( iter < CIPSO_V4_TAG_MAXCNT )
doi_def - > tags [ iter + + ] = CIPSO_V4_TAG_INVALID ;
2006-09-26 02:56:37 +04:00
return 0 ;
}
2006-08-04 03:48:59 +04:00
/*
* NetLabel Command Handlers
*/
/**
* netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
2006-09-26 02:56:37 +04:00
* @ info : the Generic NETLINK info block
2006-08-04 03:48:59 +04:00
*
* Description :
* Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
* and add it to the CIPSO V4 engine . Return zero on success and non - zero on
* error .
*
*/
2006-09-26 02:56:37 +04:00
static int netlbl_cipsov4_add_std ( struct genl_info * info )
2006-08-04 03:48:59 +04:00
{
int ret_val = - EINVAL ;
struct cipso_v4_doi * doi_def = NULL ;
2006-09-26 02:56:37 +04:00
struct nlattr * nla_a ;
struct nlattr * nla_b ;
int nla_a_rem ;
int nla_b_rem ;
2006-12-16 00:49:28 +03:00
u32 iter ;
2006-08-04 03:48:59 +04:00
2006-09-29 01:51:47 +04:00
if ( ! info - > attrs [ NLBL_CIPSOV4_A_TAGLST ] | |
2006-09-26 02:56:37 +04:00
! info - > attrs [ NLBL_CIPSOV4_A_MLSLVLLST ] )
return - EINVAL ;
if ( nla_validate_nested ( info - > attrs [ NLBL_CIPSOV4_A_MLSLVLLST ] ,
NLBL_CIPSOV4_A_MAX ,
netlbl_cipsov4_genl_policy ) ! = 0 )
return - EINVAL ;
2006-08-04 03:48:59 +04:00
doi_def = kmalloc ( sizeof ( * doi_def ) , GFP_KERNEL ) ;
2006-09-26 02:56:37 +04:00
if ( doi_def = = NULL )
return - ENOMEM ;
2006-08-04 03:48:59 +04:00
doi_def - > map . std = kzalloc ( sizeof ( * doi_def - > map . std ) , GFP_KERNEL ) ;
if ( doi_def - > map . std = = NULL ) {
ret_val = - ENOMEM ;
goto add_std_failure ;
}
doi_def - > type = CIPSO_V4_MAP_STD ;
2006-09-26 02:56:37 +04:00
ret_val = netlbl_cipsov4_add_common ( info , doi_def ) ;
if ( ret_val ! = 0 )
2006-08-04 03:48:59 +04:00
goto add_std_failure ;
2006-12-16 00:49:27 +03:00
ret_val = - EINVAL ;
2006-08-04 03:48:59 +04:00
2006-09-26 02:56:37 +04:00
nla_for_each_nested ( nla_a ,
info - > attrs [ NLBL_CIPSOV4_A_MLSLVLLST ] ,
nla_a_rem )
if ( nla_a - > nla_type = = NLBL_CIPSOV4_A_MLSLVL ) {
2006-12-16 00:49:27 +03:00
if ( nla_validate_nested ( nla_a ,
NLBL_CIPSOV4_A_MAX ,
netlbl_cipsov4_genl_policy ) ! = 0 )
goto add_std_failure ;
2006-09-26 02:56:37 +04:00
nla_for_each_nested ( nla_b , nla_a , nla_b_rem )
switch ( nla_b - > nla_type ) {
case NLBL_CIPSOV4_A_MLSLVLLOC :
2006-12-16 00:49:27 +03:00
if ( nla_get_u32 ( nla_b ) >
CIPSO_V4_MAX_LOC_LVLS )
goto add_std_failure ;
2006-09-26 02:56:37 +04:00
if ( nla_get_u32 ( nla_b ) > =
doi_def - > map . std - > lvl . local_size )
doi_def - > map . std - > lvl . local_size =
nla_get_u32 ( nla_b ) + 1 ;
break ;
case NLBL_CIPSOV4_A_MLSLVLREM :
2006-12-16 00:49:27 +03:00
if ( nla_get_u32 ( nla_b ) >
CIPSO_V4_MAX_REM_LVLS )
goto add_std_failure ;
2006-09-26 02:56:37 +04:00
if ( nla_get_u32 ( nla_b ) > =
doi_def - > map . std - > lvl . cipso_size )
doi_def - > map . std - > lvl . cipso_size =
nla_get_u32 ( nla_b ) + 1 ;
break ;
}
}
2006-08-04 03:48:59 +04:00
doi_def - > map . std - > lvl . local = kcalloc ( doi_def - > map . std - > lvl . local_size ,
sizeof ( u32 ) ,
GFP_KERNEL ) ;
if ( doi_def - > map . std - > lvl . local = = NULL ) {
ret_val = - ENOMEM ;
goto add_std_failure ;
}
doi_def - > map . std - > lvl . cipso = kcalloc ( doi_def - > map . std - > lvl . cipso_size ,
sizeof ( u32 ) ,
GFP_KERNEL ) ;
if ( doi_def - > map . std - > lvl . cipso = = NULL ) {
ret_val = - ENOMEM ;
goto add_std_failure ;
}
2006-12-16 00:49:28 +03:00
for ( iter = 0 ; iter < doi_def - > map . std - > lvl . local_size ; iter + + )
doi_def - > map . std - > lvl . local [ iter ] = CIPSO_V4_INV_LVL ;
for ( iter = 0 ; iter < doi_def - > map . std - > lvl . cipso_size ; iter + + )
doi_def - > map . std - > lvl . cipso [ iter ] = CIPSO_V4_INV_LVL ;
2006-09-26 02:56:37 +04:00
nla_for_each_nested ( nla_a ,
info - > attrs [ NLBL_CIPSOV4_A_MLSLVLLST ] ,
nla_a_rem )
if ( nla_a - > nla_type = = NLBL_CIPSOV4_A_MLSLVL ) {
struct nlattr * lvl_loc ;
struct nlattr * lvl_rem ;
lvl_loc = nla_find_nested ( nla_a ,
NLBL_CIPSOV4_A_MLSLVLLOC ) ;
lvl_rem = nla_find_nested ( nla_a ,
NLBL_CIPSOV4_A_MLSLVLREM ) ;
if ( lvl_loc = = NULL | | lvl_rem = = NULL )
goto add_std_failure ;
doi_def - > map . std - > lvl . local [ nla_get_u32 ( lvl_loc ) ] =
nla_get_u32 ( lvl_rem ) ;
doi_def - > map . std - > lvl . cipso [ nla_get_u32 ( lvl_rem ) ] =
nla_get_u32 ( lvl_loc ) ;
}
2006-08-04 03:48:59 +04:00
2006-09-26 02:56:37 +04:00
if ( info - > attrs [ NLBL_CIPSOV4_A_MLSCATLST ] ) {
if ( nla_validate_nested ( info - > attrs [ NLBL_CIPSOV4_A_MLSCATLST ] ,
NLBL_CIPSOV4_A_MAX ,
netlbl_cipsov4_genl_policy ) ! = 0 )
goto add_std_failure ;
nla_for_each_nested ( nla_a ,
info - > attrs [ NLBL_CIPSOV4_A_MLSCATLST ] ,
nla_a_rem )
if ( nla_a - > nla_type = = NLBL_CIPSOV4_A_MLSCAT ) {
if ( nla_validate_nested ( nla_a ,
NLBL_CIPSOV4_A_MAX ,
netlbl_cipsov4_genl_policy ) ! = 0 )
goto add_std_failure ;
nla_for_each_nested ( nla_b , nla_a , nla_b_rem )
switch ( nla_b - > nla_type ) {
case NLBL_CIPSOV4_A_MLSCATLOC :
2006-12-16 00:49:27 +03:00
if ( nla_get_u32 ( nla_b ) >
CIPSO_V4_MAX_LOC_CATS )
goto add_std_failure ;
2006-09-26 02:56:37 +04:00
if ( nla_get_u32 ( nla_b ) > =
doi_def - > map . std - > cat . local_size )
doi_def - > map . std - > cat . local_size =
nla_get_u32 ( nla_b ) + 1 ;
break ;
case NLBL_CIPSOV4_A_MLSCATREM :
2006-12-16 00:49:27 +03:00
if ( nla_get_u32 ( nla_b ) >
CIPSO_V4_MAX_REM_CATS )
goto add_std_failure ;
2006-09-26 02:56:37 +04:00
if ( nla_get_u32 ( nla_b ) > =
doi_def - > map . std - > cat . cipso_size )
doi_def - > map . std - > cat . cipso_size =
nla_get_u32 ( nla_b ) + 1 ;
break ;
}
}
doi_def - > map . std - > cat . local = kcalloc (
2007-02-09 17:25:05 +03:00
doi_def - > map . std - > cat . local_size ,
2006-08-04 03:48:59 +04:00
sizeof ( u32 ) ,
GFP_KERNEL ) ;
2006-09-26 02:56:37 +04:00
if ( doi_def - > map . std - > cat . local = = NULL ) {
ret_val = - ENOMEM ;
goto add_std_failure ;
}
doi_def - > map . std - > cat . cipso = kcalloc (
2007-02-09 17:25:05 +03:00
doi_def - > map . std - > cat . cipso_size ,
2006-08-04 03:48:59 +04:00
sizeof ( u32 ) ,
GFP_KERNEL ) ;
2006-09-26 02:56:37 +04:00
if ( doi_def - > map . std - > cat . cipso = = NULL ) {
ret_val = - ENOMEM ;
2006-08-04 03:48:59 +04:00
goto add_std_failure ;
2006-09-26 02:56:37 +04:00
}
2006-12-16 00:49:28 +03:00
for ( iter = 0 ; iter < doi_def - > map . std - > cat . local_size ; iter + + )
doi_def - > map . std - > cat . local [ iter ] = CIPSO_V4_INV_CAT ;
for ( iter = 0 ; iter < doi_def - > map . std - > cat . cipso_size ; iter + + )
doi_def - > map . std - > cat . cipso [ iter ] = CIPSO_V4_INV_CAT ;
2006-09-26 02:56:37 +04:00
nla_for_each_nested ( nla_a ,
info - > attrs [ NLBL_CIPSOV4_A_MLSCATLST ] ,
nla_a_rem )
if ( nla_a - > nla_type = = NLBL_CIPSOV4_A_MLSCAT ) {
struct nlattr * cat_loc ;
struct nlattr * cat_rem ;
cat_loc = nla_find_nested ( nla_a ,
NLBL_CIPSOV4_A_MLSCATLOC ) ;
cat_rem = nla_find_nested ( nla_a ,
NLBL_CIPSOV4_A_MLSCATREM ) ;
if ( cat_loc = = NULL | | cat_rem = = NULL )
goto add_std_failure ;
doi_def - > map . std - > cat . local [
2007-02-09 17:25:05 +03:00
nla_get_u32 ( cat_loc ) ] =
2006-09-26 02:56:37 +04:00
nla_get_u32 ( cat_rem ) ;
doi_def - > map . std - > cat . cipso [
2007-02-09 17:25:05 +03:00
nla_get_u32 ( cat_rem ) ] =
2006-09-26 02:56:37 +04:00
nla_get_u32 ( cat_loc ) ;
}
2006-08-04 03:48:59 +04:00
}
ret_val = cipso_v4_doi_add ( doi_def ) ;
if ( ret_val ! = 0 )
goto add_std_failure ;
return 0 ;
add_std_failure :
if ( doi_def )
netlbl_cipsov4_doi_free ( & doi_def - > rcu ) ;
return ret_val ;
}
/**
* netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
2006-09-26 02:56:37 +04:00
* @ info : the Generic NETLINK info block
2006-08-04 03:48:59 +04:00
*
* Description :
* Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
* and add it to the CIPSO V4 engine . Return zero on success and non - zero on
* error .
*
*/
2006-09-26 02:56:37 +04:00
static int netlbl_cipsov4_add_pass ( struct genl_info * info )
2006-08-04 03:48:59 +04:00
{
2006-09-26 02:56:37 +04:00
int ret_val ;
2006-08-04 03:48:59 +04:00
struct cipso_v4_doi * doi_def = NULL ;
2006-09-29 01:51:47 +04:00
if ( ! info - > attrs [ NLBL_CIPSOV4_A_TAGLST ] )
2006-09-26 02:56:37 +04:00
return - EINVAL ;
2006-08-04 03:48:59 +04:00
doi_def = kmalloc ( sizeof ( * doi_def ) , GFP_KERNEL ) ;
2006-09-26 02:56:37 +04:00
if ( doi_def = = NULL )
return - ENOMEM ;
2006-08-04 03:48:59 +04:00
doi_def - > type = CIPSO_V4_MAP_PASS ;
2006-09-26 02:56:37 +04:00
ret_val = netlbl_cipsov4_add_common ( info , doi_def ) ;
if ( ret_val ! = 0 )
goto add_pass_failure ;
2006-08-04 03:48:59 +04:00
ret_val = cipso_v4_doi_add ( doi_def ) ;
if ( ret_val ! = 0 )
goto add_pass_failure ;
return 0 ;
add_pass_failure :
2006-09-26 02:56:37 +04:00
netlbl_cipsov4_doi_free ( & doi_def - > rcu ) ;
2006-08-04 03:48:59 +04:00
return ret_val ;
}
/**
* netlbl_cipsov4_add - Handle an ADD message
* @ skb : the NETLINK buffer
* @ info : the Generic NETLINK info block
*
* Description :
* Create a new DOI definition based on the given ADD message and add it to the
* CIPSO V4 engine . Returns zero on success , negative values on failure .
*
*/
static int netlbl_cipsov4_add ( struct sk_buff * skb , struct genl_info * info )
{
int ret_val = - EINVAL ;
2006-09-29 01:51:47 +04:00
u32 type ;
u32 doi ;
const char * type_str = " (unknown) " ;
struct audit_buffer * audit_buf ;
2006-09-30 04:05:05 +04:00
struct netlbl_audit audit_info ;
2006-08-04 03:48:59 +04:00
2006-09-29 01:51:47 +04:00
if ( ! info - > attrs [ NLBL_CIPSOV4_A_DOI ] | |
! info - > attrs [ NLBL_CIPSOV4_A_MTYPE ] )
2006-09-26 02:56:37 +04:00
return - EINVAL ;
2006-08-04 03:48:59 +04:00
2006-09-30 04:05:05 +04:00
doi = nla_get_u32 ( info - > attrs [ NLBL_CIPSOV4_A_DOI ] ) ;
netlbl_netlink_auditinfo ( skb , & audit_info ) ;
2006-09-29 01:51:47 +04:00
type = nla_get_u32 ( info - > attrs [ NLBL_CIPSOV4_A_MTYPE ] ) ;
switch ( type ) {
2006-08-04 03:48:59 +04:00
case CIPSO_V4_MAP_STD :
2006-09-29 01:51:47 +04:00
type_str = " std " ;
2006-09-26 02:56:37 +04:00
ret_val = netlbl_cipsov4_add_std ( info ) ;
2006-08-04 03:48:59 +04:00
break ;
case CIPSO_V4_MAP_PASS :
2006-09-29 01:51:47 +04:00
type_str = " pass " ;
2006-09-26 02:56:37 +04:00
ret_val = netlbl_cipsov4_add_pass ( info ) ;
2006-08-04 03:48:59 +04:00
break ;
}
2007-07-18 20:28:45 +04:00
if ( ret_val = = 0 )
netlbl_mgmt_protocount_inc ( ) ;
2006-08-04 03:48:59 +04:00
2006-09-30 04:05:05 +04:00
audit_buf = netlbl_audit_start_common ( AUDIT_MAC_CIPSOV4_ADD ,
& audit_info ) ;
2006-11-18 01:38:55 +03:00
if ( audit_buf ! = NULL ) {
audit_log_format ( audit_buf ,
" cipso_doi=%u cipso_type=%s res=%u " ,
doi ,
type_str ,
ret_val = = 0 ? 1 : 0 ) ;
audit_log_end ( audit_buf ) ;
}
2006-09-29 01:51:47 +04:00
2006-08-04 03:48:59 +04:00
return ret_val ;
}
/**
* netlbl_cipsov4_list - Handle a LIST message
* @ skb : the NETLINK buffer
* @ info : the Generic NETLINK info block
*
* Description :
2006-09-26 02:56:37 +04:00
* Process a user generated LIST message and respond accordingly . While the
* response message generated by the kernel is straightforward , determining
* before hand the size of the buffer to allocate is not ( we have to generate
* the message to know the size ) . In order to keep this function sane what we
* do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
* that size , if we fail then we restart with a larger buffer and try again .
* We continue in this manner until we hit a limit of failed attempts then we
* give up and just send an error message . Returns zero on success and
* negative values on error .
2006-08-04 03:48:59 +04:00
*
*/
static int netlbl_cipsov4_list ( struct sk_buff * skb , struct genl_info * info )
{
2006-09-26 02:56:37 +04:00
int ret_val ;
struct sk_buff * ans_skb = NULL ;
u32 nlsze_mult = 1 ;
void * data ;
2006-08-04 03:48:59 +04:00
u32 doi ;
2006-09-26 02:56:37 +04:00
struct nlattr * nla_a ;
struct nlattr * nla_b ;
struct cipso_v4_doi * doi_def ;
u32 iter ;
2006-08-04 03:48:59 +04:00
2006-09-26 02:56:37 +04:00
if ( ! info - > attrs [ NLBL_CIPSOV4_A_DOI ] ) {
ret_val = - EINVAL ;
2006-08-04 03:48:59 +04:00
goto list_failure ;
2006-09-26 02:56:37 +04:00
}
2006-08-04 03:48:59 +04:00
2006-09-26 02:56:37 +04:00
list_start :
2006-11-11 01:10:15 +03:00
ans_skb = nlmsg_new ( NLMSG_DEFAULT_SIZE * nlsze_mult , GFP_KERNEL ) ;
2006-08-04 03:48:59 +04:00
if ( ans_skb = = NULL ) {
ret_val = - ENOMEM ;
goto list_failure ;
}
2006-11-15 06:46:02 +03:00
data = genlmsg_put_reply ( ans_skb , info , & netlbl_cipsov4_gnl_family ,
0 , NLBL_CIPSOV4_C_LIST ) ;
2006-09-26 02:56:37 +04:00
if ( data = = NULL ) {
ret_val = - ENOMEM ;
goto list_failure ;
}
doi = nla_get_u32 ( info - > attrs [ NLBL_CIPSOV4_A_DOI ] ) ;
rcu_read_lock ( ) ;
doi_def = cipso_v4_doi_getdef ( doi ) ;
if ( doi_def = = NULL ) {
ret_val = - EINVAL ;
goto list_failure ;
}
ret_val = nla_put_u32 ( ans_skb , NLBL_CIPSOV4_A_MTYPE , doi_def - > type ) ;
if ( ret_val ! = 0 )
goto list_failure_lock ;
nla_a = nla_nest_start ( ans_skb , NLBL_CIPSOV4_A_TAGLST ) ;
if ( nla_a = = NULL ) {
ret_val = - ENOMEM ;
goto list_failure_lock ;
}
for ( iter = 0 ;
iter < CIPSO_V4_TAG_MAXCNT & &
doi_def - > tags [ iter ] ! = CIPSO_V4_TAG_INVALID ;
iter + + ) {
ret_val = nla_put_u8 ( ans_skb ,
NLBL_CIPSOV4_A_TAG ,
doi_def - > tags [ iter ] ) ;
if ( ret_val ! = 0 )
goto list_failure_lock ;
}
nla_nest_end ( ans_skb , nla_a ) ;
switch ( doi_def - > type ) {
case CIPSO_V4_MAP_STD :
nla_a = nla_nest_start ( ans_skb , NLBL_CIPSOV4_A_MLSLVLLST ) ;
if ( nla_a = = NULL ) {
ret_val = - ENOMEM ;
goto list_failure_lock ;
}
for ( iter = 0 ;
iter < doi_def - > map . std - > lvl . local_size ;
iter + + ) {
if ( doi_def - > map . std - > lvl . local [ iter ] = =
CIPSO_V4_INV_LVL )
continue ;
nla_b = nla_nest_start ( ans_skb , NLBL_CIPSOV4_A_MLSLVL ) ;
if ( nla_b = = NULL ) {
ret_val = - ENOMEM ;
goto list_retry ;
}
ret_val = nla_put_u32 ( ans_skb ,
NLBL_CIPSOV4_A_MLSLVLLOC ,
iter ) ;
if ( ret_val ! = 0 )
goto list_retry ;
ret_val = nla_put_u32 ( ans_skb ,
NLBL_CIPSOV4_A_MLSLVLREM ,
doi_def - > map . std - > lvl . local [ iter ] ) ;
if ( ret_val ! = 0 )
goto list_retry ;
nla_nest_end ( ans_skb , nla_b ) ;
}
nla_nest_end ( ans_skb , nla_a ) ;
nla_a = nla_nest_start ( ans_skb , NLBL_CIPSOV4_A_MLSCATLST ) ;
if ( nla_a = = NULL ) {
ret_val = - ENOMEM ;
goto list_retry ;
}
for ( iter = 0 ;
iter < doi_def - > map . std - > cat . local_size ;
iter + + ) {
if ( doi_def - > map . std - > cat . local [ iter ] = =
CIPSO_V4_INV_CAT )
continue ;
nla_b = nla_nest_start ( ans_skb , NLBL_CIPSOV4_A_MLSCAT ) ;
if ( nla_b = = NULL ) {
ret_val = - ENOMEM ;
goto list_retry ;
}
ret_val = nla_put_u32 ( ans_skb ,
NLBL_CIPSOV4_A_MLSCATLOC ,
iter ) ;
if ( ret_val ! = 0 )
goto list_retry ;
ret_val = nla_put_u32 ( ans_skb ,
NLBL_CIPSOV4_A_MLSCATREM ,
doi_def - > map . std - > cat . local [ iter ] ) ;
if ( ret_val ! = 0 )
goto list_retry ;
nla_nest_end ( ans_skb , nla_b ) ;
}
nla_nest_end ( ans_skb , nla_a ) ;
break ;
}
rcu_read_unlock ( ) ;
2006-08-04 03:48:59 +04:00
2006-09-26 02:56:37 +04:00
genlmsg_end ( ans_skb , data ) ;
2006-11-15 06:45:27 +03:00
ret_val = genlmsg_reply ( ans_skb , info ) ;
2006-08-04 03:48:59 +04:00
if ( ret_val ! = 0 )
goto list_failure ;
return 0 ;
2006-09-26 02:56:37 +04:00
list_retry :
/* XXX - this limit is a guesstimate */
if ( nlsze_mult < 4 ) {
rcu_read_unlock ( ) ;
kfree_skb ( ans_skb ) ;
nlsze_mult + + ;
goto list_start ;
}
list_failure_lock :
rcu_read_unlock ( ) ;
2006-08-04 03:48:59 +04:00
list_failure :
2006-09-26 02:56:37 +04:00
kfree_skb ( ans_skb ) ;
return ret_val ;
}
/**
* netlbl_cipsov4_listall_cb - cipso_v4_doi_walk ( ) callback for LISTALL
* @ doi_def : the CIPSOv4 DOI definition
* @ arg : the netlbl_cipsov4_doiwalk_arg structure
*
* Description :
* This function is designed to be used as a callback to the
* cipso_v4_doi_walk ( ) function for use in generating a response for a LISTALL
* message . Returns the size of the message on success , negative values on
* failure .
*
*/
static int netlbl_cipsov4_listall_cb ( struct cipso_v4_doi * doi_def , void * arg )
{
int ret_val = - ENOMEM ;
struct netlbl_cipsov4_doiwalk_arg * cb_arg = arg ;
void * data ;
2006-11-15 06:46:02 +03:00
data = genlmsg_put ( cb_arg - > skb , NETLINK_CB ( cb_arg - > nl_cb - > skb ) . pid ,
cb_arg - > seq , & netlbl_cipsov4_gnl_family ,
NLM_F_MULTI , NLBL_CIPSOV4_C_LISTALL ) ;
2006-09-26 02:56:37 +04:00
if ( data = = NULL )
goto listall_cb_failure ;
ret_val = nla_put_u32 ( cb_arg - > skb , NLBL_CIPSOV4_A_DOI , doi_def - > doi ) ;
if ( ret_val ! = 0 )
goto listall_cb_failure ;
ret_val = nla_put_u32 ( cb_arg - > skb ,
NLBL_CIPSOV4_A_MTYPE ,
doi_def - > type ) ;
if ( ret_val ! = 0 )
goto listall_cb_failure ;
return genlmsg_end ( cb_arg - > skb , data ) ;
listall_cb_failure :
genlmsg_cancel ( cb_arg - > skb , data ) ;
2006-08-04 03:48:59 +04:00
return ret_val ;
}
/**
* netlbl_cipsov4_listall - Handle a LISTALL message
* @ skb : the NETLINK buffer
2006-09-26 02:56:37 +04:00
* @ cb : the NETLINK callback
2006-08-04 03:48:59 +04:00
*
* Description :
* Process a user generated LISTALL message and respond accordingly . Returns
* zero on success and negative values on error .
*
*/
2006-09-26 02:56:37 +04:00
static int netlbl_cipsov4_listall ( struct sk_buff * skb ,
struct netlink_callback * cb )
2006-08-04 03:48:59 +04:00
{
2006-09-26 02:56:37 +04:00
struct netlbl_cipsov4_doiwalk_arg cb_arg ;
int doi_skip = cb - > args [ 0 ] ;
2006-08-04 03:48:59 +04:00
2006-09-26 02:56:37 +04:00
cb_arg . nl_cb = cb ;
cb_arg . skb = skb ;
cb_arg . seq = cb - > nlh - > nlmsg_seq ;
2006-08-04 03:48:59 +04:00
2006-09-26 02:56:37 +04:00
cipso_v4_doi_walk ( & doi_skip , netlbl_cipsov4_listall_cb , & cb_arg ) ;
2006-08-04 03:48:59 +04:00
2006-09-26 02:56:37 +04:00
cb - > args [ 0 ] = doi_skip ;
return skb - > len ;
2006-08-04 03:48:59 +04:00
}
/**
* netlbl_cipsov4_remove - Handle a REMOVE message
* @ skb : the NETLINK buffer
* @ info : the Generic NETLINK info block
*
* Description :
* Process a user generated REMOVE message and respond accordingly . Returns
* zero on success , negative values on failure .
*
*/
static int netlbl_cipsov4_remove ( struct sk_buff * skb , struct genl_info * info )
{
2006-09-26 02:56:37 +04:00
int ret_val = - EINVAL ;
2006-09-29 01:51:47 +04:00
u32 doi = 0 ;
struct audit_buffer * audit_buf ;
2006-09-30 04:05:05 +04:00
struct netlbl_audit audit_info ;
2006-08-04 03:48:59 +04:00
2006-09-30 04:05:05 +04:00
if ( ! info - > attrs [ NLBL_CIPSOV4_A_DOI ] )
return - EINVAL ;
2006-09-29 01:51:47 +04:00
2006-09-30 04:05:05 +04:00
doi = nla_get_u32 ( info - > attrs [ NLBL_CIPSOV4_A_DOI ] ) ;
netlbl_netlink_auditinfo ( skb , & audit_info ) ;
ret_val = cipso_v4_doi_remove ( doi ,
& audit_info ,
netlbl_cipsov4_doi_free ) ;
2007-07-18 20:28:45 +04:00
if ( ret_val = = 0 )
netlbl_mgmt_protocount_dec ( ) ;
2006-09-30 04:05:05 +04:00
audit_buf = netlbl_audit_start_common ( AUDIT_MAC_CIPSOV4_DEL ,
& audit_info ) ;
2006-11-18 01:38:55 +03:00
if ( audit_buf ! = NULL ) {
audit_log_format ( audit_buf ,
" cipso_doi=%u res=%u " ,
doi ,
ret_val = = 0 ? 1 : 0 ) ;
audit_log_end ( audit_buf ) ;
}
2006-08-04 03:48:59 +04:00
return ret_val ;
}
/*
* NetLabel Generic NETLINK Command Definitions
*/
static struct genl_ops netlbl_cipsov4_genl_c_add = {
. cmd = NLBL_CIPSOV4_C_ADD ,
2006-09-26 02:56:37 +04:00
. flags = GENL_ADMIN_PERM ,
. policy = netlbl_cipsov4_genl_policy ,
2006-08-04 03:48:59 +04:00
. doit = netlbl_cipsov4_add ,
. dumpit = NULL ,
} ;
static struct genl_ops netlbl_cipsov4_genl_c_remove = {
. cmd = NLBL_CIPSOV4_C_REMOVE ,
2006-09-26 02:56:37 +04:00
. flags = GENL_ADMIN_PERM ,
. policy = netlbl_cipsov4_genl_policy ,
2006-08-04 03:48:59 +04:00
. doit = netlbl_cipsov4_remove ,
. dumpit = NULL ,
} ;
static struct genl_ops netlbl_cipsov4_genl_c_list = {
. cmd = NLBL_CIPSOV4_C_LIST ,
. flags = 0 ,
2006-09-26 02:56:37 +04:00
. policy = netlbl_cipsov4_genl_policy ,
2006-08-04 03:48:59 +04:00
. doit = netlbl_cipsov4_list ,
. dumpit = NULL ,
} ;
static struct genl_ops netlbl_cipsov4_genl_c_listall = {
. cmd = NLBL_CIPSOV4_C_LISTALL ,
. flags = 0 ,
2006-09-26 02:56:37 +04:00
. policy = netlbl_cipsov4_genl_policy ,
. doit = NULL ,
. dumpit = netlbl_cipsov4_listall ,
2006-08-04 03:48:59 +04:00
} ;
/*
* NetLabel Generic NETLINK Protocol Functions
*/
/**
* netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
*
* Description :
* Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
* mechanism . Returns zero on success , negative values on failure .
*
*/
int netlbl_cipsov4_genl_init ( void )
{
int ret_val ;
ret_val = genl_register_family ( & netlbl_cipsov4_gnl_family ) ;
if ( ret_val ! = 0 )
return ret_val ;
ret_val = genl_register_ops ( & netlbl_cipsov4_gnl_family ,
& netlbl_cipsov4_genl_c_add ) ;
if ( ret_val ! = 0 )
return ret_val ;
ret_val = genl_register_ops ( & netlbl_cipsov4_gnl_family ,
& netlbl_cipsov4_genl_c_remove ) ;
if ( ret_val ! = 0 )
return ret_val ;
ret_val = genl_register_ops ( & netlbl_cipsov4_gnl_family ,
& netlbl_cipsov4_genl_c_list ) ;
if ( ret_val ! = 0 )
return ret_val ;
ret_val = genl_register_ops ( & netlbl_cipsov4_gnl_family ,
& netlbl_cipsov4_genl_c_listall ) ;
if ( ret_val ! = 0 )
return ret_val ;
return 0 ;
}