2006-08-03 16:48:37 -07:00
/*
* NetLabel Management Support
*
* This file defines the management 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 >
*
*/
/*
2008-10-10 10:16:32 -04:00
* ( c ) Copyright Hewlett - Packard Development Company , L . P . , 2006 , 2008
2006-08-03 16:48:37 -07:00
*
* 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>
2008-10-10 10:16:32 -04:00
# include <linux/in.h>
# include <linux/in6.h>
2006-08-03 16:48:37 -07:00
# include <net/sock.h>
# include <net/netlink.h>
# include <net/genetlink.h>
2008-10-10 10:16:32 -04:00
# include <net/ip.h>
# include <net/ipv6.h>
2006-08-03 16:48:37 -07:00
# include <net/netlabel.h>
# include <net/cipso_ipv4.h>
2008-01-29 08:37:52 -05:00
# include <asm/atomic.h>
2006-08-03 16:48:37 -07:00
# include "netlabel_domainhash.h"
# include "netlabel_user.h"
# include "netlabel_mgmt.h"
2008-01-29 08:37:52 -05:00
/* NetLabel configured protocol counter */
atomic_t netlabel_mgmt_protocount = ATOMIC_INIT ( 0 ) ;
2007-07-18 12:28:45 -04:00
2006-09-25 15:56:37 -07:00
/* Argument struct for netlbl_domhsh_walk() */
struct netlbl_domhsh_walk_arg {
struct netlink_callback * nl_cb ;
struct sk_buff * skb ;
u32 seq ;
} ;
2006-08-03 16:48:37 -07:00
/* NetLabel Generic NETLINK CIPSOv4 family */
static struct genl_family netlbl_mgmt_gnl_family = {
. id = GENL_ID_GENERATE ,
. hdrsize = 0 ,
. name = NETLBL_NLTYPE_MGMT_NAME ,
. version = NETLBL_PROTO_VERSION ,
2006-09-25 15:56:37 -07:00
. maxattr = NLBL_MGMT_A_MAX ,
2006-08-03 16:48:37 -07:00
} ;
2006-09-25 15:56:37 -07:00
/* NetLabel Netlink attribute policy */
2007-06-05 12:38:30 -07:00
static const struct nla_policy netlbl_mgmt_genl_policy [ NLBL_MGMT_A_MAX + 1 ] = {
2006-09-25 15:56:37 -07:00
[ NLBL_MGMT_A_DOMAIN ] = { . type = NLA_NUL_STRING } ,
[ NLBL_MGMT_A_PROTOCOL ] = { . type = NLA_U32 } ,
[ NLBL_MGMT_A_VERSION ] = { . type = NLA_U32 } ,
[ NLBL_MGMT_A_CV4DOI ] = { . type = NLA_U32 } ,
} ;
2006-08-03 16:48:37 -07:00
/*
2008-10-10 10:16:32 -04:00
* Helper Functions
2006-08-03 16:48:37 -07:00
*/
/**
* netlbl_mgmt_add - Handle an ADD message
* @ info : the Generic NETLINK info block
2008-10-10 10:16:32 -04:00
* @ audit_info : NetLabel audit information
2006-08-03 16:48:37 -07:00
*
* Description :
2008-10-10 10:16:32 -04:00
* Helper function for the ADD and ADDDEF messages to add the domain mappings
* from the message to the hash table . See netlabel . h for a description of the
* message format . Returns zero on success , negative values on failure .
2006-08-03 16:48:37 -07:00
*
*/
2008-10-10 10:16:32 -04:00
static int netlbl_mgmt_add_common ( struct genl_info * info ,
struct netlbl_audit * audit_info )
2006-08-03 16:48:37 -07:00
{
int ret_val = - EINVAL ;
struct netlbl_dom_map * entry = NULL ;
2008-10-10 10:16:32 -04:00
struct netlbl_domaddr_map * addrmap = NULL ;
struct cipso_v4_doi * cipsov4 = NULL ;
2006-08-03 16:48:37 -07:00
u32 tmp_val ;
2006-09-29 17:05:05 -07:00
2006-09-25 15:56:37 -07:00
entry = kzalloc ( sizeof ( * entry ) , GFP_KERNEL ) ;
if ( entry = = NULL ) {
ret_val = - ENOMEM ;
goto add_failure ;
}
entry - > type = nla_get_u32 ( info - > attrs [ NLBL_MGMT_A_PROTOCOL ] ) ;
2008-10-10 10:16:32 -04:00
if ( info - > attrs [ NLBL_MGMT_A_DOMAIN ] ) {
size_t tmp_size = nla_len ( info - > attrs [ NLBL_MGMT_A_DOMAIN ] ) ;
entry - > domain = kmalloc ( tmp_size , GFP_KERNEL ) ;
if ( entry - > domain = = NULL ) {
ret_val = - ENOMEM ;
goto add_failure ;
}
nla_strlcpy ( entry - > domain ,
info - > attrs [ NLBL_MGMT_A_DOMAIN ] , tmp_size ) ;
}
/* NOTE: internally we allow/use a entry->type value of
* NETLBL_NLTYPE_ADDRSELECT but we don ' t currently allow users
* to pass that as a protocol value because we need to know the
* " real " protocol */
2006-08-03 16:48:37 -07:00
2006-09-25 15:56:37 -07:00
switch ( entry - > type ) {
case NETLBL_NLTYPE_UNLABELED :
break ;
case NETLBL_NLTYPE_CIPSOV4 :
if ( ! info - > attrs [ NLBL_MGMT_A_CV4DOI ] )
2006-08-03 16:48:37 -07:00
goto add_failure ;
2006-09-25 15:56:37 -07:00
tmp_val = nla_get_u32 ( info - > attrs [ NLBL_MGMT_A_CV4DOI ] ) ;
2008-10-10 10:16:32 -04:00
cipsov4 = cipso_v4_doi_getdef ( tmp_val ) ;
if ( cipsov4 = = NULL )
2006-08-03 16:48:37 -07:00
goto add_failure ;
2008-10-10 10:16:32 -04:00
entry - > type_def . cipsov4 = cipsov4 ;
2006-09-25 15:56:37 -07:00
break ;
default :
goto add_failure ;
2006-08-03 16:48:37 -07:00
}
2008-10-10 10:16:32 -04:00
if ( info - > attrs [ NLBL_MGMT_A_IPV4ADDR ] ) {
struct in_addr * addr ;
struct in_addr * mask ;
struct netlbl_domaddr4_map * map ;
addrmap = kzalloc ( sizeof ( * addrmap ) , GFP_KERNEL ) ;
if ( addrmap = = NULL ) {
ret_val = - ENOMEM ;
goto add_failure ;
}
INIT_LIST_HEAD ( & addrmap - > list4 ) ;
INIT_LIST_HEAD ( & addrmap - > list6 ) ;
if ( nla_len ( info - > attrs [ NLBL_MGMT_A_IPV4ADDR ] ) ! =
sizeof ( struct in_addr ) ) {
ret_val = - EINVAL ;
goto add_failure ;
}
if ( nla_len ( info - > attrs [ NLBL_MGMT_A_IPV4MASK ] ) ! =
sizeof ( struct in_addr ) ) {
ret_val = - EINVAL ;
goto add_failure ;
}
addr = nla_data ( info - > attrs [ NLBL_MGMT_A_IPV4ADDR ] ) ;
mask = nla_data ( info - > attrs [ NLBL_MGMT_A_IPV4MASK ] ) ;
map = kzalloc ( sizeof ( * map ) , GFP_KERNEL ) ;
if ( map = = NULL ) {
ret_val = - ENOMEM ;
goto add_failure ;
}
map - > list . addr = addr - > s_addr & mask - > s_addr ;
map - > list . mask = mask - > s_addr ;
map - > list . valid = 1 ;
map - > type = entry - > type ;
if ( cipsov4 )
map - > type_def . cipsov4 = cipsov4 ;
ret_val = netlbl_af4list_add ( & map - > list , & addrmap - > list4 ) ;
if ( ret_val ! = 0 ) {
kfree ( map ) ;
goto add_failure ;
}
entry - > type = NETLBL_NLTYPE_ADDRSELECT ;
entry - > type_def . addrsel = addrmap ;
# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
} else if ( info - > attrs [ NLBL_MGMT_A_IPV6ADDR ] ) {
struct in6_addr * addr ;
struct in6_addr * mask ;
struct netlbl_domaddr6_map * map ;
addrmap = kzalloc ( sizeof ( * addrmap ) , GFP_KERNEL ) ;
if ( addrmap = = NULL ) {
ret_val = - ENOMEM ;
goto add_failure ;
}
INIT_LIST_HEAD ( & addrmap - > list4 ) ;
INIT_LIST_HEAD ( & addrmap - > list6 ) ;
if ( nla_len ( info - > attrs [ NLBL_MGMT_A_IPV6ADDR ] ) ! =
sizeof ( struct in6_addr ) ) {
ret_val = - EINVAL ;
goto add_failure ;
}
if ( nla_len ( info - > attrs [ NLBL_MGMT_A_IPV6MASK ] ) ! =
sizeof ( struct in6_addr ) ) {
ret_val = - EINVAL ;
goto add_failure ;
}
addr = nla_data ( info - > attrs [ NLBL_MGMT_A_IPV6ADDR ] ) ;
mask = nla_data ( info - > attrs [ NLBL_MGMT_A_IPV6MASK ] ) ;
map = kzalloc ( sizeof ( * map ) , GFP_KERNEL ) ;
if ( map = = NULL ) {
ret_val = - ENOMEM ;
goto add_failure ;
}
ipv6_addr_copy ( & map - > list . addr , addr ) ;
map - > list . addr . s6_addr32 [ 0 ] & = mask - > s6_addr32 [ 0 ] ;
map - > list . addr . s6_addr32 [ 1 ] & = mask - > s6_addr32 [ 1 ] ;
map - > list . addr . s6_addr32 [ 2 ] & = mask - > s6_addr32 [ 2 ] ;
map - > list . addr . s6_addr32 [ 3 ] & = mask - > s6_addr32 [ 3 ] ;
ipv6_addr_copy ( & map - > list . mask , mask ) ;
map - > list . valid = 1 ;
map - > type = entry - > type ;
ret_val = netlbl_af6list_add ( & map - > list , & addrmap - > list6 ) ;
if ( ret_val ! = 0 ) {
kfree ( map ) ;
goto add_failure ;
}
entry - > type = NETLBL_NLTYPE_ADDRSELECT ;
entry - > type_def . addrsel = addrmap ;
# endif /* IPv6 */
}
ret_val = netlbl_domhsh_add ( entry , audit_info ) ;
2006-09-25 15:56:37 -07:00
if ( ret_val ! = 0 )
goto add_failure ;
2006-08-03 16:48:37 -07:00
return 0 ;
add_failure :
2008-10-10 10:16:32 -04:00
if ( cipsov4 )
cipso_v4_doi_putdef ( cipsov4 ) ;
2006-08-03 16:48:37 -07:00
if ( entry )
kfree ( entry - > domain ) ;
2008-10-10 10:16:32 -04:00
kfree ( addrmap ) ;
2006-08-03 16:48:37 -07:00
kfree ( entry ) ;
return ret_val ;
}
2008-10-10 10:16:32 -04:00
/**
* netlbl_mgmt_listentry - List a NetLabel / LSM domain map entry
* @ skb : the NETLINK buffer
* @ entry : the map entry
*
* Description :
* This function is a helper function used by the LISTALL and LISTDEF command
* handlers . The caller is responsibile for ensuring that the RCU read lock
* is held . Returns zero on success , negative values on failure .
*
*/
static int netlbl_mgmt_listentry ( struct sk_buff * skb ,
struct netlbl_dom_map * entry )
{
int ret_val ;
struct nlattr * nla_a ;
struct nlattr * nla_b ;
struct netlbl_af4list * iter4 ;
# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct netlbl_af6list * iter6 ;
# endif
if ( entry - > domain ! = NULL ) {
ret_val = nla_put_string ( skb ,
NLBL_MGMT_A_DOMAIN , entry - > domain ) ;
if ( ret_val ! = 0 )
return ret_val ;
}
switch ( entry - > type ) {
case NETLBL_NLTYPE_ADDRSELECT :
nla_a = nla_nest_start ( skb , NLBL_MGMT_A_SELECTORLIST ) ;
if ( nla_a = = NULL )
return - ENOMEM ;
netlbl_af4list_foreach_rcu ( iter4 ,
& entry - > type_def . addrsel - > list4 ) {
struct netlbl_domaddr4_map * map4 ;
struct in_addr addr_struct ;
nla_b = nla_nest_start ( skb , NLBL_MGMT_A_ADDRSELECTOR ) ;
if ( nla_b = = NULL )
return - ENOMEM ;
addr_struct . s_addr = iter4 - > addr ;
ret_val = nla_put ( skb , NLBL_MGMT_A_IPV4ADDR ,
sizeof ( struct in_addr ) ,
& addr_struct ) ;
if ( ret_val ! = 0 )
return ret_val ;
addr_struct . s_addr = iter4 - > mask ;
ret_val = nla_put ( skb , NLBL_MGMT_A_IPV4MASK ,
sizeof ( struct in_addr ) ,
& addr_struct ) ;
if ( ret_val ! = 0 )
return ret_val ;
map4 = netlbl_domhsh_addr4_entry ( iter4 ) ;
ret_val = nla_put_u32 ( skb , NLBL_MGMT_A_PROTOCOL ,
map4 - > type ) ;
if ( ret_val ! = 0 )
return ret_val ;
switch ( map4 - > type ) {
case NETLBL_NLTYPE_CIPSOV4 :
ret_val = nla_put_u32 ( skb , NLBL_MGMT_A_CV4DOI ,
map4 - > type_def . cipsov4 - > doi ) ;
if ( ret_val ! = 0 )
return ret_val ;
break ;
}
nla_nest_end ( skb , nla_b ) ;
}
# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
netlbl_af6list_foreach_rcu ( iter6 ,
& entry - > type_def . addrsel - > list6 ) {
struct netlbl_domaddr6_map * map6 ;
nla_b = nla_nest_start ( skb , NLBL_MGMT_A_ADDRSELECTOR ) ;
if ( nla_b = = NULL )
return - ENOMEM ;
ret_val = nla_put ( skb , NLBL_MGMT_A_IPV6ADDR ,
sizeof ( struct in6_addr ) ,
& iter6 - > addr ) ;
if ( ret_val ! = 0 )
return ret_val ;
ret_val = nla_put ( skb , NLBL_MGMT_A_IPV6MASK ,
sizeof ( struct in6_addr ) ,
& iter6 - > mask ) ;
if ( ret_val ! = 0 )
return ret_val ;
map6 = netlbl_domhsh_addr6_entry ( iter6 ) ;
ret_val = nla_put_u32 ( skb , NLBL_MGMT_A_PROTOCOL ,
map6 - > type ) ;
if ( ret_val ! = 0 )
return ret_val ;
nla_nest_end ( skb , nla_b ) ;
}
# endif /* IPv6 */
nla_nest_end ( skb , nla_a ) ;
break ;
case NETLBL_NLTYPE_UNLABELED :
ret_val = nla_put_u32 ( skb , NLBL_MGMT_A_PROTOCOL , entry - > type ) ;
break ;
case NETLBL_NLTYPE_CIPSOV4 :
ret_val = nla_put_u32 ( skb , NLBL_MGMT_A_PROTOCOL , entry - > type ) ;
if ( ret_val ! = 0 )
return ret_val ;
ret_val = nla_put_u32 ( skb , NLBL_MGMT_A_CV4DOI ,
entry - > type_def . cipsov4 - > doi ) ;
break ;
}
return ret_val ;
}
/*
* NetLabel Command Handlers
*/
/**
* netlbl_mgmt_add - Handle an ADD message
* @ skb : the NETLINK buffer
* @ info : the Generic NETLINK info block
*
* Description :
* Process a user generated ADD message and add the domains from the message
* to the hash table . See netlabel . h for a description of the message format .
* Returns zero on success , negative values on failure .
*
*/
static int netlbl_mgmt_add ( struct sk_buff * skb , struct genl_info * info )
{
struct netlbl_audit audit_info ;
if ( ( ! info - > attrs [ NLBL_MGMT_A_DOMAIN ] ) | |
( ! info - > attrs [ NLBL_MGMT_A_PROTOCOL ] ) | |
( info - > attrs [ NLBL_MGMT_A_IPV4ADDR ] & &
info - > attrs [ NLBL_MGMT_A_IPV6ADDR ] ) | |
( info - > attrs [ NLBL_MGMT_A_IPV4MASK ] & &
info - > attrs [ NLBL_MGMT_A_IPV6MASK ] ) | |
( ( info - > attrs [ NLBL_MGMT_A_IPV4ADDR ] ! = NULL ) ^
( info - > attrs [ NLBL_MGMT_A_IPV4MASK ] ! = NULL ) ) | |
( ( info - > attrs [ NLBL_MGMT_A_IPV6ADDR ] ! = NULL ) ^
( info - > attrs [ NLBL_MGMT_A_IPV6MASK ] ! = NULL ) ) )
return - EINVAL ;
netlbl_netlink_auditinfo ( skb , & audit_info ) ;
return netlbl_mgmt_add_common ( info , & audit_info ) ;
}
2006-08-03 16:48:37 -07:00
/**
* netlbl_mgmt_remove - Handle a REMOVE message
* @ skb : the NETLINK buffer
* @ info : the Generic NETLINK info block
*
* Description :
* Process a user generated REMOVE message and remove the specified domain
* mappings . Returns zero on success , negative values on failure .
*
*/
static int netlbl_mgmt_remove ( struct sk_buff * skb , struct genl_info * info )
{
2006-09-25 15:56:37 -07:00
char * domain ;
2006-09-29 17:05:05 -07:00
struct netlbl_audit audit_info ;
2006-08-03 16:48:37 -07:00
2006-09-25 15:56:37 -07:00
if ( ! info - > attrs [ NLBL_MGMT_A_DOMAIN ] )
return - EINVAL ;
2006-08-03 16:48:37 -07:00
2006-09-29 17:05:05 -07:00
netlbl_netlink_auditinfo ( skb , & audit_info ) ;
2006-09-25 15:56:37 -07:00
domain = nla_data ( info - > attrs [ NLBL_MGMT_A_DOMAIN ] ) ;
2006-09-29 17:05:05 -07:00
return netlbl_domhsh_remove ( domain , & audit_info ) ;
2006-09-25 15:56:37 -07:00
}
/**
* netlbl_mgmt_listall_cb - netlbl_domhsh_walk ( ) callback for LISTALL
* @ entry : the domain mapping hash table entry
* @ arg : the netlbl_domhsh_walk_arg structure
*
* Description :
* This function is designed to be used as a callback to the
* netlbl_domhsh_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_mgmt_listall_cb ( struct netlbl_dom_map * entry , void * arg )
{
int ret_val = - ENOMEM ;
struct netlbl_domhsh_walk_arg * cb_arg = arg ;
void * data ;
2006-11-14 19:46:02 -08:00
data = genlmsg_put ( cb_arg - > skb , NETLINK_CB ( cb_arg - > nl_cb - > skb ) . pid ,
cb_arg - > seq , & netlbl_mgmt_gnl_family ,
NLM_F_MULTI , NLBL_MGMT_C_LISTALL ) ;
2006-09-25 15:56:37 -07:00
if ( data = = NULL )
goto listall_cb_failure ;
2008-10-10 10:16:32 -04:00
ret_val = netlbl_mgmt_listentry ( cb_arg - > skb , entry ) ;
2006-09-25 15:56:37 -07:00
if ( ret_val ! = 0 )
goto listall_cb_failure ;
2006-08-03 16:48:37 -07:00
2006-09-25 15:56:37 -07:00
cb_arg - > seq + + ;
return genlmsg_end ( cb_arg - > skb , data ) ;
2006-08-03 16:48:37 -07:00
2006-09-25 15:56:37 -07:00
listall_cb_failure :
genlmsg_cancel ( cb_arg - > skb , data ) ;
2006-08-03 16:48:37 -07:00
return ret_val ;
}
/**
2006-09-25 15:56:37 -07:00
* netlbl_mgmt_listall - Handle a LISTALL message
2006-08-03 16:48:37 -07:00
* @ skb : the NETLINK buffer
2006-09-25 15:56:37 -07:00
* @ cb : the NETLINK callback
2006-08-03 16:48:37 -07:00
*
* Description :
2006-09-25 15:56:37 -07:00
* Process a user generated LISTALL message and dumps the domain hash table in
* a form suitable for use in a kernel generated LISTALL message . Returns zero
* on success , negative values on failure .
2006-08-03 16:48:37 -07:00
*
*/
2006-09-25 15:56:37 -07:00
static int netlbl_mgmt_listall ( struct sk_buff * skb ,
struct netlink_callback * cb )
2006-08-03 16:48:37 -07:00
{
2006-09-25 15:56:37 -07:00
struct netlbl_domhsh_walk_arg cb_arg ;
u32 skip_bkt = cb - > args [ 0 ] ;
u32 skip_chain = cb - > args [ 1 ] ;
cb_arg . nl_cb = cb ;
cb_arg . skb = skb ;
cb_arg . seq = cb - > nlh - > nlmsg_seq ;
netlbl_domhsh_walk ( & skip_bkt ,
& skip_chain ,
netlbl_mgmt_listall_cb ,
& cb_arg ) ;
cb - > args [ 0 ] = skip_bkt ;
cb - > args [ 1 ] = skip_chain ;
return skb - > len ;
2006-08-03 16:48:37 -07:00
}
/**
* netlbl_mgmt_adddef - Handle an ADDDEF message
* @ skb : the NETLINK buffer
* @ info : the Generic NETLINK info block
*
* Description :
* Process a user generated ADDDEF message and respond accordingly . Returns
* zero on success , negative values on failure .
*
*/
static int netlbl_mgmt_adddef ( struct sk_buff * skb , struct genl_info * info )
{
2006-09-29 17:05:05 -07:00
struct netlbl_audit audit_info ;
2006-08-03 16:48:37 -07:00
2008-10-10 10:16:32 -04:00
if ( ( ! info - > attrs [ NLBL_MGMT_A_PROTOCOL ] ) | |
( info - > attrs [ NLBL_MGMT_A_IPV4ADDR ] & &
info - > attrs [ NLBL_MGMT_A_IPV6ADDR ] ) | |
( info - > attrs [ NLBL_MGMT_A_IPV4MASK ] & &
info - > attrs [ NLBL_MGMT_A_IPV6MASK ] ) | |
( ( info - > attrs [ NLBL_MGMT_A_IPV4ADDR ] ! = NULL ) ^
( info - > attrs [ NLBL_MGMT_A_IPV4MASK ] ! = NULL ) ) | |
( ( info - > attrs [ NLBL_MGMT_A_IPV6ADDR ] ! = NULL ) ^
( info - > attrs [ NLBL_MGMT_A_IPV6MASK ] ! = NULL ) ) )
return - EINVAL ;
2006-08-03 16:48:37 -07:00
2006-09-29 17:05:05 -07:00
netlbl_netlink_auditinfo ( skb , & audit_info ) ;
2008-10-10 10:16:32 -04:00
return netlbl_mgmt_add_common ( info , & audit_info ) ;
2006-08-03 16:48:37 -07:00
}
/**
* netlbl_mgmt_removedef - Handle a REMOVEDEF message
* @ skb : the NETLINK buffer
* @ info : the Generic NETLINK info block
*
* Description :
* Process a user generated REMOVEDEF message and remove the default domain
* mapping . Returns zero on success , negative values on failure .
*
*/
static int netlbl_mgmt_removedef ( struct sk_buff * skb , struct genl_info * info )
{
2006-09-29 17:05:05 -07:00
struct netlbl_audit audit_info ;
netlbl_netlink_auditinfo ( skb , & audit_info ) ;
return netlbl_domhsh_remove_default ( & audit_info ) ;
2006-08-03 16:48:37 -07:00
}
/**
* netlbl_mgmt_listdef - Handle a LISTDEF message
* @ skb : the NETLINK buffer
* @ info : the Generic NETLINK info block
*
* Description :
* Process a user generated LISTDEF message and dumps the default domain
* mapping in a form suitable for use in a kernel generated LISTDEF message .
* Returns zero on success , negative values on failure .
*
*/
static int netlbl_mgmt_listdef ( struct sk_buff * skb , struct genl_info * info )
{
int ret_val = - ENOMEM ;
2006-09-25 15:56:37 -07:00
struct sk_buff * ans_skb = NULL ;
void * data ;
struct netlbl_dom_map * entry ;
2006-08-03 16:48:37 -07:00
2006-11-10 14:10:15 -08:00
ans_skb = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
2006-08-03 16:48:37 -07:00
if ( ans_skb = = NULL )
2006-09-25 15:56:37 -07:00
return - ENOMEM ;
2006-11-14 19:46:02 -08:00
data = genlmsg_put_reply ( ans_skb , info , & netlbl_mgmt_gnl_family ,
0 , NLBL_MGMT_C_LISTDEF ) ;
2006-09-25 15:56:37 -07:00
if ( data = = NULL )
2006-08-03 16:48:37 -07:00
goto listdef_failure ;
2006-09-25 15:56:37 -07:00
rcu_read_lock ( ) ;
entry = netlbl_domhsh_getentry ( NULL ) ;
if ( entry = = NULL ) {
ret_val = - ENOENT ;
goto listdef_failure_lock ;
}
2008-10-10 10:16:32 -04:00
ret_val = netlbl_mgmt_listentry ( ans_skb , entry ) ;
2006-09-25 15:56:37 -07:00
rcu_read_unlock ( ) ;
2008-10-10 10:16:32 -04:00
if ( ret_val ! = 0 )
goto listdef_failure ;
2006-08-03 16:48:37 -07:00
2006-09-25 15:56:37 -07:00
genlmsg_end ( ans_skb , data ) ;
2008-07-10 16:53:39 -07:00
return genlmsg_reply ( ans_skb , info ) ;
2006-08-03 16:48:37 -07:00
2006-09-25 15:56:37 -07:00
listdef_failure_lock :
rcu_read_unlock ( ) ;
2006-08-03 16:48:37 -07:00
listdef_failure :
2006-09-25 15:56:37 -07:00
kfree_skb ( ans_skb ) ;
2006-08-03 16:48:37 -07:00
return ret_val ;
}
/**
2006-09-25 15:56:37 -07:00
* netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
* @ skb : the skb to write to
* @ seq : the NETLINK sequence number
* @ cb : the NETLINK callback
* @ protocol : the NetLabel protocol to use in the message
2006-08-03 16:48:37 -07:00
*
* Description :
2006-09-25 15:56:37 -07:00
* This function is to be used in conjunction with netlbl_mgmt_protocols ( ) to
* answer a application ' s PROTOCOLS message . Returns the size of the message
* on success , negative values on failure .
2006-08-03 16:48:37 -07:00
*
*/
2006-09-25 15:56:37 -07:00
static int netlbl_mgmt_protocols_cb ( struct sk_buff * skb ,
struct netlink_callback * cb ,
u32 protocol )
2006-08-03 16:48:37 -07:00
{
int ret_val = - ENOMEM ;
2006-09-25 15:56:37 -07:00
void * data ;
2006-11-14 19:46:02 -08:00
data = genlmsg_put ( skb , NETLINK_CB ( cb - > skb ) . pid , cb - > nlh - > nlmsg_seq ,
& netlbl_mgmt_gnl_family , NLM_F_MULTI ,
NLBL_MGMT_C_PROTOCOLS ) ;
2006-09-25 15:56:37 -07:00
if ( data = = NULL )
goto protocols_cb_failure ;
ret_val = nla_put_u32 ( skb , NLBL_MGMT_A_PROTOCOL , protocol ) ;
2006-08-03 16:48:37 -07:00
if ( ret_val ! = 0 )
2006-09-25 15:56:37 -07:00
goto protocols_cb_failure ;
2006-08-03 16:48:37 -07:00
2006-09-25 15:56:37 -07:00
return genlmsg_end ( skb , data ) ;
2006-08-03 16:48:37 -07:00
2006-09-25 15:56:37 -07:00
protocols_cb_failure :
genlmsg_cancel ( skb , data ) ;
2006-08-03 16:48:37 -07:00
return ret_val ;
}
2006-09-25 15:56:37 -07:00
/**
* netlbl_mgmt_protocols - Handle a PROTOCOLS message
* @ skb : the NETLINK buffer
* @ cb : the NETLINK callback
*
* Description :
* Process a user generated PROTOCOLS message and respond accordingly .
*
*/
static int netlbl_mgmt_protocols ( struct sk_buff * skb ,
struct netlink_callback * cb )
{
u32 protos_sent = cb - > args [ 0 ] ;
if ( protos_sent = = 0 ) {
if ( netlbl_mgmt_protocols_cb ( skb ,
cb ,
NETLBL_NLTYPE_UNLABELED ) < 0 )
goto protocols_return ;
protos_sent + + ;
}
if ( protos_sent = = 1 ) {
if ( netlbl_mgmt_protocols_cb ( skb ,
cb ,
NETLBL_NLTYPE_CIPSOV4 ) < 0 )
goto protocols_return ;
protos_sent + + ;
}
protocols_return :
cb - > args [ 0 ] = protos_sent ;
return skb - > len ;
}
2006-08-03 16:48:37 -07:00
/**
* netlbl_mgmt_version - Handle a VERSION message
* @ skb : the NETLINK buffer
* @ info : the Generic NETLINK info block
*
* Description :
* Process a user generated VERSION message and respond accordingly . Returns
* zero on success , negative values on failure .
*
*/
static int netlbl_mgmt_version ( struct sk_buff * skb , struct genl_info * info )
{
int ret_val = - ENOMEM ;
struct sk_buff * ans_skb = NULL ;
2006-09-25 15:56:37 -07:00
void * data ;
2006-08-03 16:48:37 -07:00
2006-11-10 14:10:15 -08:00
ans_skb = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
2006-08-03 16:48:37 -07:00
if ( ans_skb = = NULL )
2006-09-25 15:56:37 -07:00
return - ENOMEM ;
2006-11-14 19:46:02 -08:00
data = genlmsg_put_reply ( ans_skb , info , & netlbl_mgmt_gnl_family ,
0 , NLBL_MGMT_C_VERSION ) ;
2006-09-25 15:56:37 -07:00
if ( data = = NULL )
2006-08-03 16:48:37 -07:00
goto version_failure ;
2006-09-25 15:56:37 -07:00
ret_val = nla_put_u32 ( ans_skb ,
NLBL_MGMT_A_VERSION ,
NETLBL_PROTO_VERSION ) ;
2006-08-03 16:48:37 -07:00
if ( ret_val ! = 0 )
goto version_failure ;
2006-09-25 15:56:37 -07:00
genlmsg_end ( ans_skb , data ) ;
2008-07-10 16:53:39 -07:00
return genlmsg_reply ( ans_skb , info ) ;
2006-08-03 16:48:37 -07:00
version_failure :
kfree_skb ( ans_skb ) ;
return ret_val ;
}
/*
* NetLabel Generic NETLINK Command Definitions
*/
2008-02-17 22:33:16 -08:00
static struct genl_ops netlbl_mgmt_genl_ops [ ] = {
{
2006-08-03 16:48:37 -07:00
. cmd = NLBL_MGMT_C_ADD ,
2006-09-25 15:56:37 -07:00
. flags = GENL_ADMIN_PERM ,
. policy = netlbl_mgmt_genl_policy ,
2006-08-03 16:48:37 -07:00
. doit = netlbl_mgmt_add ,
. dumpit = NULL ,
2008-02-17 22:33:16 -08:00
} ,
{
2006-08-03 16:48:37 -07:00
. cmd = NLBL_MGMT_C_REMOVE ,
2006-09-25 15:56:37 -07:00
. flags = GENL_ADMIN_PERM ,
. policy = netlbl_mgmt_genl_policy ,
2006-08-03 16:48:37 -07:00
. doit = netlbl_mgmt_remove ,
. dumpit = NULL ,
2008-02-17 22:33:16 -08:00
} ,
{
2006-09-25 15:56:37 -07:00
. cmd = NLBL_MGMT_C_LISTALL ,
2006-08-03 16:48:37 -07:00
. flags = 0 ,
2006-09-25 15:56:37 -07:00
. policy = netlbl_mgmt_genl_policy ,
. doit = NULL ,
. dumpit = netlbl_mgmt_listall ,
2008-02-17 22:33:16 -08:00
} ,
{
2006-08-03 16:48:37 -07:00
. cmd = NLBL_MGMT_C_ADDDEF ,
2006-09-25 15:56:37 -07:00
. flags = GENL_ADMIN_PERM ,
. policy = netlbl_mgmt_genl_policy ,
2006-08-03 16:48:37 -07:00
. doit = netlbl_mgmt_adddef ,
. dumpit = NULL ,
2008-02-17 22:33:16 -08:00
} ,
{
2006-08-03 16:48:37 -07:00
. cmd = NLBL_MGMT_C_REMOVEDEF ,
2006-09-25 15:56:37 -07:00
. flags = GENL_ADMIN_PERM ,
. policy = netlbl_mgmt_genl_policy ,
2006-08-03 16:48:37 -07:00
. doit = netlbl_mgmt_removedef ,
. dumpit = NULL ,
2008-02-17 22:33:16 -08:00
} ,
{
2006-08-03 16:48:37 -07:00
. cmd = NLBL_MGMT_C_LISTDEF ,
. flags = 0 ,
2006-09-25 15:56:37 -07:00
. policy = netlbl_mgmt_genl_policy ,
2006-08-03 16:48:37 -07:00
. doit = netlbl_mgmt_listdef ,
. dumpit = NULL ,
2008-02-17 22:33:16 -08:00
} ,
{
2006-09-25 15:56:37 -07:00
. cmd = NLBL_MGMT_C_PROTOCOLS ,
2006-08-03 16:48:37 -07:00
. flags = 0 ,
2006-09-25 15:56:37 -07:00
. policy = netlbl_mgmt_genl_policy ,
. doit = NULL ,
. dumpit = netlbl_mgmt_protocols ,
2008-02-17 22:33:16 -08:00
} ,
{
2006-08-03 16:48:37 -07:00
. cmd = NLBL_MGMT_C_VERSION ,
. flags = 0 ,
2006-09-25 15:56:37 -07:00
. policy = netlbl_mgmt_genl_policy ,
2006-08-03 16:48:37 -07:00
. doit = netlbl_mgmt_version ,
. dumpit = NULL ,
2008-02-17 22:33:16 -08:00
} ,
2006-08-03 16:48:37 -07:00
} ;
/*
* NetLabel Generic NETLINK Protocol Functions
*/
/**
* netlbl_mgmt_genl_init - Register the NetLabel management component
*
* Description :
* Register the NetLabel management component with the Generic NETLINK
* mechanism . Returns zero on success , negative values on failure .
*
*/
2008-02-17 22:33:57 -08:00
int __init netlbl_mgmt_genl_init ( void )
2006-08-03 16:48:37 -07:00
{
2008-02-17 22:33:16 -08:00
int ret_val , i ;
2006-08-03 16:48:37 -07:00
ret_val = genl_register_family ( & netlbl_mgmt_gnl_family ) ;
if ( ret_val ! = 0 )
return ret_val ;
2008-02-17 22:33:16 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( netlbl_mgmt_genl_ops ) ; i + + ) {
ret_val = genl_register_ops ( & netlbl_mgmt_gnl_family ,
& netlbl_mgmt_genl_ops [ i ] ) ;
if ( ret_val ! = 0 )
return ret_val ;
}
2006-08-03 16:48:37 -07:00
return 0 ;
}