xref: /openbmc/linux/net/netlabel/netlabel_mgmt.c (revision 23bcdc1a)
1d15c345fSPaul Moore /*
2d15c345fSPaul Moore  * NetLabel Management Support
3d15c345fSPaul Moore  *
4d15c345fSPaul Moore  * This file defines the management functions for the NetLabel system.  The
5d15c345fSPaul Moore  * NetLabel system manages static and dynamic label mappings for network
6d15c345fSPaul Moore  * protocols such as CIPSO and RIPSO.
7d15c345fSPaul Moore  *
8d15c345fSPaul Moore  * Author: Paul Moore <paul.moore@hp.com>
9d15c345fSPaul Moore  *
10d15c345fSPaul Moore  */
11d15c345fSPaul Moore 
12d15c345fSPaul Moore /*
13d15c345fSPaul Moore  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14d15c345fSPaul Moore  *
15d15c345fSPaul Moore  * This program is free software;  you can redistribute it and/or modify
16d15c345fSPaul Moore  * it under the terms of the GNU General Public License as published by
17d15c345fSPaul Moore  * the Free Software Foundation; either version 2 of the License, or
18d15c345fSPaul Moore  * (at your option) any later version.
19d15c345fSPaul Moore  *
20d15c345fSPaul Moore  * This program is distributed in the hope that it will be useful,
21d15c345fSPaul Moore  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
22d15c345fSPaul Moore  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
23d15c345fSPaul Moore  * the GNU General Public License for more details.
24d15c345fSPaul Moore  *
25d15c345fSPaul Moore  * You should have received a copy of the GNU General Public License
26d15c345fSPaul Moore  * along with this program;  if not, write to the Free Software
27d15c345fSPaul Moore  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28d15c345fSPaul Moore  *
29d15c345fSPaul Moore  */
30d15c345fSPaul Moore 
31d15c345fSPaul Moore #include <linux/types.h>
32d15c345fSPaul Moore #include <linux/socket.h>
33d15c345fSPaul Moore #include <linux/string.h>
34d15c345fSPaul Moore #include <linux/skbuff.h>
35d15c345fSPaul Moore #include <net/sock.h>
36d15c345fSPaul Moore #include <net/netlink.h>
37d15c345fSPaul Moore #include <net/genetlink.h>
38d15c345fSPaul Moore #include <net/netlabel.h>
39d15c345fSPaul Moore #include <net/cipso_ipv4.h>
40d15c345fSPaul Moore 
41d15c345fSPaul Moore #include "netlabel_domainhash.h"
42d15c345fSPaul Moore #include "netlabel_user.h"
43d15c345fSPaul Moore #include "netlabel_mgmt.h"
44d15c345fSPaul Moore 
4523bcdc1aSPaul Moore /* NetLabel configured protocol count */
4623bcdc1aSPaul Moore static DEFINE_SPINLOCK(netlabel_mgmt_protocount_lock);
4723bcdc1aSPaul Moore static u32 netlabel_mgmt_protocount = 0;
4823bcdc1aSPaul Moore 
49fd385855SPaul Moore /* Argument struct for netlbl_domhsh_walk() */
50fd385855SPaul Moore struct netlbl_domhsh_walk_arg {
51fd385855SPaul Moore 	struct netlink_callback *nl_cb;
52fd385855SPaul Moore 	struct sk_buff *skb;
53fd385855SPaul Moore 	u32 seq;
54fd385855SPaul Moore };
55fd385855SPaul Moore 
56d15c345fSPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */
57d15c345fSPaul Moore static struct genl_family netlbl_mgmt_gnl_family = {
58d15c345fSPaul Moore 	.id = GENL_ID_GENERATE,
59d15c345fSPaul Moore 	.hdrsize = 0,
60d15c345fSPaul Moore 	.name = NETLBL_NLTYPE_MGMT_NAME,
61d15c345fSPaul Moore 	.version = NETLBL_PROTO_VERSION,
62fd385855SPaul Moore 	.maxattr = NLBL_MGMT_A_MAX,
63d15c345fSPaul Moore };
64d15c345fSPaul Moore 
65fd385855SPaul Moore /* NetLabel Netlink attribute policy */
66ef7c79edSPatrick McHardy static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
67fd385855SPaul Moore 	[NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
68fd385855SPaul Moore 	[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
69fd385855SPaul Moore 	[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
70fd385855SPaul Moore 	[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
71fd385855SPaul Moore };
72d15c345fSPaul Moore 
73d15c345fSPaul Moore /*
7423bcdc1aSPaul Moore  * NetLabel Misc Managment Functions
7523bcdc1aSPaul Moore  */
7623bcdc1aSPaul Moore 
7723bcdc1aSPaul Moore /**
7823bcdc1aSPaul Moore  * netlbl_mgmt_protocount_inc - Increment the configured labeled protocol count
7923bcdc1aSPaul Moore  *
8023bcdc1aSPaul Moore  * Description:
8123bcdc1aSPaul Moore  * Increment the number of labeled protocol configurations in the current
8223bcdc1aSPaul Moore  * NetLabel configuration.  Keep track of this for use in determining if
8323bcdc1aSPaul Moore  * NetLabel label enforcement should be active/enabled or not in the LSM.
8423bcdc1aSPaul Moore  *
8523bcdc1aSPaul Moore  */
8623bcdc1aSPaul Moore void netlbl_mgmt_protocount_inc(void)
8723bcdc1aSPaul Moore {
8823bcdc1aSPaul Moore 	rcu_read_lock();
8923bcdc1aSPaul Moore 	spin_lock(&netlabel_mgmt_protocount_lock);
9023bcdc1aSPaul Moore 	netlabel_mgmt_protocount++;
9123bcdc1aSPaul Moore 	spin_unlock(&netlabel_mgmt_protocount_lock);
9223bcdc1aSPaul Moore 	rcu_read_unlock();
9323bcdc1aSPaul Moore }
9423bcdc1aSPaul Moore 
9523bcdc1aSPaul Moore /**
9623bcdc1aSPaul Moore  * netlbl_mgmt_protocount_dec - Decrement the configured labeled protocol count
9723bcdc1aSPaul Moore  *
9823bcdc1aSPaul Moore  * Description:
9923bcdc1aSPaul Moore  * Decrement the number of labeled protocol configurations in the current
10023bcdc1aSPaul Moore  * NetLabel configuration.  Keep track of this for use in determining if
10123bcdc1aSPaul Moore  * NetLabel label enforcement should be active/enabled or not in the LSM.
10223bcdc1aSPaul Moore  *
10323bcdc1aSPaul Moore  */
10423bcdc1aSPaul Moore void netlbl_mgmt_protocount_dec(void)
10523bcdc1aSPaul Moore {
10623bcdc1aSPaul Moore 	rcu_read_lock();
10723bcdc1aSPaul Moore 	spin_lock(&netlabel_mgmt_protocount_lock);
10823bcdc1aSPaul Moore 	if (netlabel_mgmt_protocount > 0)
10923bcdc1aSPaul Moore 		netlabel_mgmt_protocount--;
11023bcdc1aSPaul Moore 	spin_unlock(&netlabel_mgmt_protocount_lock);
11123bcdc1aSPaul Moore 	rcu_read_unlock();
11223bcdc1aSPaul Moore }
11323bcdc1aSPaul Moore 
11423bcdc1aSPaul Moore /**
11523bcdc1aSPaul Moore  * netlbl_mgmt_protocount_value - Return the number of configured protocols
11623bcdc1aSPaul Moore  *
11723bcdc1aSPaul Moore  * Description:
11823bcdc1aSPaul Moore  * Return the number of labeled protocols in the current NetLabel
11923bcdc1aSPaul Moore  * configuration.  This value is useful in  determining if NetLabel label
12023bcdc1aSPaul Moore  * enforcement should be active/enabled or not in the LSM.
12123bcdc1aSPaul Moore  *
12223bcdc1aSPaul Moore  */
12323bcdc1aSPaul Moore u32 netlbl_mgmt_protocount_value(void)
12423bcdc1aSPaul Moore {
12523bcdc1aSPaul Moore 	u32 val;
12623bcdc1aSPaul Moore 
12723bcdc1aSPaul Moore 	rcu_read_lock();
12823bcdc1aSPaul Moore 	val = netlabel_mgmt_protocount;
12923bcdc1aSPaul Moore 	rcu_read_unlock();
13023bcdc1aSPaul Moore 
13123bcdc1aSPaul Moore 	return val;
13223bcdc1aSPaul Moore }
13323bcdc1aSPaul Moore 
13423bcdc1aSPaul Moore /*
135d15c345fSPaul Moore  * NetLabel Command Handlers
136d15c345fSPaul Moore  */
137d15c345fSPaul Moore 
138d15c345fSPaul Moore /**
139d15c345fSPaul Moore  * netlbl_mgmt_add - Handle an ADD message
140d15c345fSPaul Moore  * @skb: the NETLINK buffer
141d15c345fSPaul Moore  * @info: the Generic NETLINK info block
142d15c345fSPaul Moore  *
143d15c345fSPaul Moore  * Description:
144d15c345fSPaul Moore  * Process a user generated ADD message and add the domains from the message
145d15c345fSPaul Moore  * to the hash table.  See netlabel.h for a description of the message format.
146d15c345fSPaul Moore  * Returns zero on success, negative values on failure.
147d15c345fSPaul Moore  *
148d15c345fSPaul Moore  */
149d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
150d15c345fSPaul Moore {
151d15c345fSPaul Moore 	int ret_val = -EINVAL;
152d15c345fSPaul Moore 	struct netlbl_dom_map *entry = NULL;
153fd385855SPaul Moore 	size_t tmp_size;
154d15c345fSPaul Moore 	u32 tmp_val;
15595d4e6beSPaul Moore 	struct netlbl_audit audit_info;
156d15c345fSPaul Moore 
157fd385855SPaul Moore 	if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
158fd385855SPaul Moore 	    !info->attrs[NLBL_MGMT_A_PROTOCOL])
159d15c345fSPaul Moore 		goto add_failure;
160d15c345fSPaul Moore 
16195d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
16295d4e6beSPaul Moore 
163d15c345fSPaul Moore 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
164d15c345fSPaul Moore 	if (entry == NULL) {
165d15c345fSPaul Moore 		ret_val = -ENOMEM;
166d15c345fSPaul Moore 		goto add_failure;
167d15c345fSPaul Moore 	}
168fd385855SPaul Moore 	tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
169d15c345fSPaul Moore 	entry->domain = kmalloc(tmp_size, GFP_KERNEL);
170d15c345fSPaul Moore 	if (entry->domain == NULL) {
171d15c345fSPaul Moore 		ret_val = -ENOMEM;
172d15c345fSPaul Moore 		goto add_failure;
173d15c345fSPaul Moore 	}
174fd385855SPaul Moore 	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
175fd385855SPaul Moore 	nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
176d15c345fSPaul Moore 
177fd385855SPaul Moore 	switch (entry->type) {
178d15c345fSPaul Moore 	case NETLBL_NLTYPE_UNLABELED:
17995d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add(entry, &audit_info);
180d15c345fSPaul Moore 		break;
181d15c345fSPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
182fd385855SPaul Moore 		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
183d15c345fSPaul Moore 			goto add_failure;
184fd385855SPaul Moore 
185fd385855SPaul Moore 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
186fd385855SPaul Moore 		/* We should be holding a rcu_read_lock() here while we hold
187fd385855SPaul Moore 		 * the result but since the entry will always be deleted when
188fd385855SPaul Moore 		 * the CIPSO DOI is deleted we aren't going to keep the
189fd385855SPaul Moore 		 * lock. */
190d15c345fSPaul Moore 		rcu_read_lock();
191d15c345fSPaul Moore 		entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
192d15c345fSPaul Moore 		if (entry->type_def.cipsov4 == NULL) {
193d15c345fSPaul Moore 			rcu_read_unlock();
194d15c345fSPaul Moore 			goto add_failure;
195d15c345fSPaul Moore 		}
19695d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add(entry, &audit_info);
197d15c345fSPaul Moore 		rcu_read_unlock();
198d15c345fSPaul Moore 		break;
199d15c345fSPaul Moore 	default:
200fd385855SPaul Moore 		goto add_failure;
201d15c345fSPaul Moore 	}
202d15c345fSPaul Moore 	if (ret_val != 0)
203d15c345fSPaul Moore 		goto add_failure;
204d15c345fSPaul Moore 
205d15c345fSPaul Moore 	return 0;
206d15c345fSPaul Moore 
207d15c345fSPaul Moore add_failure:
208d15c345fSPaul Moore 	if (entry)
209d15c345fSPaul Moore 		kfree(entry->domain);
210d15c345fSPaul Moore 	kfree(entry);
211d15c345fSPaul Moore 	return ret_val;
212d15c345fSPaul Moore }
213d15c345fSPaul Moore 
214d15c345fSPaul Moore /**
215d15c345fSPaul Moore  * netlbl_mgmt_remove - Handle a REMOVE message
216d15c345fSPaul Moore  * @skb: the NETLINK buffer
217d15c345fSPaul Moore  * @info: the Generic NETLINK info block
218d15c345fSPaul Moore  *
219d15c345fSPaul Moore  * Description:
220d15c345fSPaul Moore  * Process a user generated REMOVE message and remove the specified domain
221d15c345fSPaul Moore  * mappings.  Returns zero on success, negative values on failure.
222d15c345fSPaul Moore  *
223d15c345fSPaul Moore  */
224d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
225d15c345fSPaul Moore {
226fd385855SPaul Moore 	char *domain;
22795d4e6beSPaul Moore 	struct netlbl_audit audit_info;
228d15c345fSPaul Moore 
229fd385855SPaul Moore 	if (!info->attrs[NLBL_MGMT_A_DOMAIN])
230fd385855SPaul Moore 		return -EINVAL;
231d15c345fSPaul Moore 
23295d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
23395d4e6beSPaul Moore 
234fd385855SPaul Moore 	domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
23595d4e6beSPaul Moore 	return netlbl_domhsh_remove(domain, &audit_info);
236d15c345fSPaul Moore }
237d15c345fSPaul Moore 
238fd385855SPaul Moore /**
239fd385855SPaul Moore  * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
240fd385855SPaul Moore  * @entry: the domain mapping hash table entry
241fd385855SPaul Moore  * @arg: the netlbl_domhsh_walk_arg structure
242fd385855SPaul Moore  *
243fd385855SPaul Moore  * Description:
244fd385855SPaul Moore  * This function is designed to be used as a callback to the
245fd385855SPaul Moore  * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
246fd385855SPaul Moore  * message.  Returns the size of the message on success, negative values on
247fd385855SPaul Moore  * failure.
248fd385855SPaul Moore  *
249fd385855SPaul Moore  */
250fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
251fd385855SPaul Moore {
252fd385855SPaul Moore 	int ret_val = -ENOMEM;
253fd385855SPaul Moore 	struct netlbl_domhsh_walk_arg *cb_arg = arg;
254fd385855SPaul Moore 	void *data;
255d15c345fSPaul Moore 
25617c157c8SThomas Graf 	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
25717c157c8SThomas Graf 			   cb_arg->seq, &netlbl_mgmt_gnl_family,
25817c157c8SThomas Graf 			   NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
259fd385855SPaul Moore 	if (data == NULL)
260fd385855SPaul Moore 		goto listall_cb_failure;
261fd385855SPaul Moore 
262fd385855SPaul Moore 	ret_val = nla_put_string(cb_arg->skb,
263fd385855SPaul Moore 				 NLBL_MGMT_A_DOMAIN,
264fd385855SPaul Moore 				 entry->domain);
265fd385855SPaul Moore 	if (ret_val != 0)
266fd385855SPaul Moore 		goto listall_cb_failure;
267fd385855SPaul Moore 	ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
268fd385855SPaul Moore 	if (ret_val != 0)
269fd385855SPaul Moore 		goto listall_cb_failure;
270fd385855SPaul Moore 	switch (entry->type) {
271fd385855SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
272fd385855SPaul Moore 		ret_val = nla_put_u32(cb_arg->skb,
273fd385855SPaul Moore 				      NLBL_MGMT_A_CV4DOI,
274fd385855SPaul Moore 				      entry->type_def.cipsov4->doi);
275fd385855SPaul Moore 		if (ret_val != 0)
276fd385855SPaul Moore 			goto listall_cb_failure;
277fd385855SPaul Moore 		break;
278fd385855SPaul Moore 	}
279fd385855SPaul Moore 
280fd385855SPaul Moore 	cb_arg->seq++;
281fd385855SPaul Moore 	return genlmsg_end(cb_arg->skb, data);
282fd385855SPaul Moore 
283fd385855SPaul Moore listall_cb_failure:
284fd385855SPaul Moore 	genlmsg_cancel(cb_arg->skb, data);
285d15c345fSPaul Moore 	return ret_val;
286d15c345fSPaul Moore }
287d15c345fSPaul Moore 
288d15c345fSPaul Moore /**
289fd385855SPaul Moore  * netlbl_mgmt_listall - Handle a LISTALL message
290d15c345fSPaul Moore  * @skb: the NETLINK buffer
291fd385855SPaul Moore  * @cb: the NETLINK callback
292d15c345fSPaul Moore  *
293d15c345fSPaul Moore  * Description:
294fd385855SPaul Moore  * Process a user generated LISTALL message and dumps the domain hash table in
295fd385855SPaul Moore  * a form suitable for use in a kernel generated LISTALL message.  Returns zero
296fd385855SPaul Moore  * on success, negative values on failure.
297d15c345fSPaul Moore  *
298d15c345fSPaul Moore  */
299fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb,
300fd385855SPaul Moore 			       struct netlink_callback *cb)
301d15c345fSPaul Moore {
302fd385855SPaul Moore 	struct netlbl_domhsh_walk_arg cb_arg;
303fd385855SPaul Moore 	u32 skip_bkt = cb->args[0];
304fd385855SPaul Moore 	u32 skip_chain = cb->args[1];
305d15c345fSPaul Moore 
306fd385855SPaul Moore 	cb_arg.nl_cb = cb;
307fd385855SPaul Moore 	cb_arg.skb = skb;
308fd385855SPaul Moore 	cb_arg.seq = cb->nlh->nlmsg_seq;
309d15c345fSPaul Moore 
310fd385855SPaul Moore 	netlbl_domhsh_walk(&skip_bkt,
311fd385855SPaul Moore 			   &skip_chain,
312fd385855SPaul Moore 			   netlbl_mgmt_listall_cb,
313fd385855SPaul Moore 			   &cb_arg);
314d15c345fSPaul Moore 
315fd385855SPaul Moore 	cb->args[0] = skip_bkt;
316fd385855SPaul Moore 	cb->args[1] = skip_chain;
317fd385855SPaul Moore 	return skb->len;
318d15c345fSPaul Moore }
319d15c345fSPaul Moore 
320d15c345fSPaul Moore /**
321d15c345fSPaul Moore  * netlbl_mgmt_adddef - Handle an ADDDEF message
322d15c345fSPaul Moore  * @skb: the NETLINK buffer
323d15c345fSPaul Moore  * @info: the Generic NETLINK info block
324d15c345fSPaul Moore  *
325d15c345fSPaul Moore  * Description:
326d15c345fSPaul Moore  * Process a user generated ADDDEF message and respond accordingly.  Returns
327d15c345fSPaul Moore  * zero on success, negative values on failure.
328d15c345fSPaul Moore  *
329d15c345fSPaul Moore  */
330d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
331d15c345fSPaul Moore {
332d15c345fSPaul Moore 	int ret_val = -EINVAL;
333d15c345fSPaul Moore 	struct netlbl_dom_map *entry = NULL;
334d15c345fSPaul Moore 	u32 tmp_val;
33595d4e6beSPaul Moore 	struct netlbl_audit audit_info;
336d15c345fSPaul Moore 
337fd385855SPaul Moore 	if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
338d15c345fSPaul Moore 		goto adddef_failure;
339d15c345fSPaul Moore 
34095d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
34195d4e6beSPaul Moore 
342d15c345fSPaul Moore 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
343d15c345fSPaul Moore 	if (entry == NULL) {
344d15c345fSPaul Moore 		ret_val = -ENOMEM;
345d15c345fSPaul Moore 		goto adddef_failure;
346d15c345fSPaul Moore 	}
347fd385855SPaul Moore 	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
348d15c345fSPaul Moore 
349d15c345fSPaul Moore 	switch (entry->type) {
350d15c345fSPaul Moore 	case NETLBL_NLTYPE_UNLABELED:
35195d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add_default(entry, &audit_info);
352d15c345fSPaul Moore 		break;
353d15c345fSPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
354fd385855SPaul Moore 		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
355d15c345fSPaul Moore 			goto adddef_failure;
356fd385855SPaul Moore 
357fd385855SPaul Moore 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
358fd385855SPaul Moore 		/* We should be holding a rcu_read_lock() here while we hold
359fd385855SPaul Moore 		 * the result but since the entry will always be deleted when
360fd385855SPaul Moore 		 * the CIPSO DOI is deleted we aren't going to keep the
361fd385855SPaul Moore 		 * lock. */
362d15c345fSPaul Moore 		rcu_read_lock();
363d15c345fSPaul Moore 		entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
364d15c345fSPaul Moore 		if (entry->type_def.cipsov4 == NULL) {
365d15c345fSPaul Moore 			rcu_read_unlock();
366d15c345fSPaul Moore 			goto adddef_failure;
367d15c345fSPaul Moore 		}
36895d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add_default(entry, &audit_info);
369d15c345fSPaul Moore 		rcu_read_unlock();
370d15c345fSPaul Moore 		break;
371d15c345fSPaul Moore 	default:
372fd385855SPaul Moore 		goto adddef_failure;
373d15c345fSPaul Moore 	}
374d15c345fSPaul Moore 	if (ret_val != 0)
375d15c345fSPaul Moore 		goto adddef_failure;
376d15c345fSPaul Moore 
377d15c345fSPaul Moore 	return 0;
378d15c345fSPaul Moore 
379d15c345fSPaul Moore adddef_failure:
380d15c345fSPaul Moore 	kfree(entry);
381d15c345fSPaul Moore 	return ret_val;
382d15c345fSPaul Moore }
383d15c345fSPaul Moore 
384d15c345fSPaul Moore /**
385d15c345fSPaul Moore  * netlbl_mgmt_removedef - Handle a REMOVEDEF message
386d15c345fSPaul Moore  * @skb: the NETLINK buffer
387d15c345fSPaul Moore  * @info: the Generic NETLINK info block
388d15c345fSPaul Moore  *
389d15c345fSPaul Moore  * Description:
390d15c345fSPaul Moore  * Process a user generated REMOVEDEF message and remove the default domain
391d15c345fSPaul Moore  * mapping.  Returns zero on success, negative values on failure.
392d15c345fSPaul Moore  *
393d15c345fSPaul Moore  */
394d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
395d15c345fSPaul Moore {
39695d4e6beSPaul Moore 	struct netlbl_audit audit_info;
39795d4e6beSPaul Moore 
39895d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
39995d4e6beSPaul Moore 
40095d4e6beSPaul Moore 	return netlbl_domhsh_remove_default(&audit_info);
401d15c345fSPaul Moore }
402d15c345fSPaul Moore 
403d15c345fSPaul Moore /**
404d15c345fSPaul Moore  * netlbl_mgmt_listdef - Handle a LISTDEF message
405d15c345fSPaul Moore  * @skb: the NETLINK buffer
406d15c345fSPaul Moore  * @info: the Generic NETLINK info block
407d15c345fSPaul Moore  *
408d15c345fSPaul Moore  * Description:
409d15c345fSPaul Moore  * Process a user generated LISTDEF message and dumps the default domain
410d15c345fSPaul Moore  * mapping in a form suitable for use in a kernel generated LISTDEF message.
411d15c345fSPaul Moore  * Returns zero on success, negative values on failure.
412d15c345fSPaul Moore  *
413d15c345fSPaul Moore  */
414d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
415d15c345fSPaul Moore {
416d15c345fSPaul Moore 	int ret_val = -ENOMEM;
417fd385855SPaul Moore 	struct sk_buff *ans_skb = NULL;
418fd385855SPaul Moore 	void *data;
419fd385855SPaul Moore 	struct netlbl_dom_map *entry;
420d15c345fSPaul Moore 
421339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
422d15c345fSPaul Moore 	if (ans_skb == NULL)
423fd385855SPaul Moore 		return -ENOMEM;
42417c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
42517c157c8SThomas Graf 				 0, NLBL_MGMT_C_LISTDEF);
426fd385855SPaul Moore 	if (data == NULL)
427fd385855SPaul Moore 		goto listdef_failure;
428d15c345fSPaul Moore 
429fd385855SPaul Moore 	rcu_read_lock();
430fd385855SPaul Moore 	entry = netlbl_domhsh_getentry(NULL);
431fd385855SPaul Moore 	if (entry == NULL) {
432fd385855SPaul Moore 		ret_val = -ENOENT;
433fd385855SPaul Moore 		goto listdef_failure_lock;
434fd385855SPaul Moore 	}
435fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
436fd385855SPaul Moore 	if (ret_val != 0)
437fd385855SPaul Moore 		goto listdef_failure_lock;
438fd385855SPaul Moore 	switch (entry->type) {
439fd385855SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
440fd385855SPaul Moore 		ret_val = nla_put_u32(ans_skb,
441fd385855SPaul Moore 				      NLBL_MGMT_A_CV4DOI,
442fd385855SPaul Moore 				      entry->type_def.cipsov4->doi);
443fd385855SPaul Moore 		if (ret_val != 0)
444fd385855SPaul Moore 			goto listdef_failure_lock;
445fd385855SPaul Moore 		break;
446fd385855SPaul Moore 	}
447fd385855SPaul Moore 	rcu_read_unlock();
448fd385855SPaul Moore 
449fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
450fd385855SPaul Moore 
45181878d27SThomas Graf 	ret_val = genlmsg_reply(ans_skb, info);
452d15c345fSPaul Moore 	if (ret_val != 0)
453d15c345fSPaul Moore 		goto listdef_failure;
454d15c345fSPaul Moore 	return 0;
455d15c345fSPaul Moore 
456fd385855SPaul Moore listdef_failure_lock:
457fd385855SPaul Moore 	rcu_read_unlock();
458d15c345fSPaul Moore listdef_failure:
459fd385855SPaul Moore 	kfree_skb(ans_skb);
460d15c345fSPaul Moore 	return ret_val;
461d15c345fSPaul Moore }
462d15c345fSPaul Moore 
463d15c345fSPaul Moore /**
464fd385855SPaul Moore  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
465fd385855SPaul Moore  * @skb: the skb to write to
466fd385855SPaul Moore  * @seq: the NETLINK sequence number
467fd385855SPaul Moore  * @cb: the NETLINK callback
468fd385855SPaul Moore  * @protocol: the NetLabel protocol to use in the message
469d15c345fSPaul Moore  *
470d15c345fSPaul Moore  * Description:
471fd385855SPaul Moore  * This function is to be used in conjunction with netlbl_mgmt_protocols() to
472fd385855SPaul Moore  * answer a application's PROTOCOLS message.  Returns the size of the message
473fd385855SPaul Moore  * on success, negative values on failure.
474d15c345fSPaul Moore  *
475d15c345fSPaul Moore  */
476fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
477fd385855SPaul Moore 				    struct netlink_callback *cb,
478fd385855SPaul Moore 				    u32 protocol)
479d15c345fSPaul Moore {
480d15c345fSPaul Moore 	int ret_val = -ENOMEM;
481fd385855SPaul Moore 	void *data;
482d15c345fSPaul Moore 
48317c157c8SThomas Graf 	data = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
48417c157c8SThomas Graf 			   &netlbl_mgmt_gnl_family, NLM_F_MULTI,
485fd385855SPaul Moore 			   NLBL_MGMT_C_PROTOCOLS);
486fd385855SPaul Moore 	if (data == NULL)
487fd385855SPaul Moore 		goto protocols_cb_failure;
488d15c345fSPaul Moore 
489fd385855SPaul Moore 	ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
490d15c345fSPaul Moore 	if (ret_val != 0)
491fd385855SPaul Moore 		goto protocols_cb_failure;
492d15c345fSPaul Moore 
493fd385855SPaul Moore 	return genlmsg_end(skb, data);
494d15c345fSPaul Moore 
495fd385855SPaul Moore protocols_cb_failure:
496fd385855SPaul Moore 	genlmsg_cancel(skb, data);
497d15c345fSPaul Moore 	return ret_val;
498d15c345fSPaul Moore }
499d15c345fSPaul Moore 
500d15c345fSPaul Moore /**
501fd385855SPaul Moore  * netlbl_mgmt_protocols - Handle a PROTOCOLS message
502fd385855SPaul Moore  * @skb: the NETLINK buffer
503fd385855SPaul Moore  * @cb: the NETLINK callback
504fd385855SPaul Moore  *
505fd385855SPaul Moore  * Description:
506fd385855SPaul Moore  * Process a user generated PROTOCOLS message and respond accordingly.
507fd385855SPaul Moore  *
508fd385855SPaul Moore  */
509fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb,
510fd385855SPaul Moore 				 struct netlink_callback *cb)
511fd385855SPaul Moore {
512fd385855SPaul Moore 	u32 protos_sent = cb->args[0];
513fd385855SPaul Moore 
514fd385855SPaul Moore 	if (protos_sent == 0) {
515fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
516fd385855SPaul Moore 					     cb,
517fd385855SPaul Moore 					     NETLBL_NLTYPE_UNLABELED) < 0)
518fd385855SPaul Moore 			goto protocols_return;
519fd385855SPaul Moore 		protos_sent++;
520fd385855SPaul Moore 	}
521fd385855SPaul Moore 	if (protos_sent == 1) {
522fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
523fd385855SPaul Moore 					     cb,
524fd385855SPaul Moore 					     NETLBL_NLTYPE_CIPSOV4) < 0)
525fd385855SPaul Moore 			goto protocols_return;
526fd385855SPaul Moore 		protos_sent++;
527fd385855SPaul Moore 	}
528fd385855SPaul Moore 
529fd385855SPaul Moore protocols_return:
530fd385855SPaul Moore 	cb->args[0] = protos_sent;
531fd385855SPaul Moore 	return skb->len;
532fd385855SPaul Moore }
533fd385855SPaul Moore 
534fd385855SPaul Moore /**
535d15c345fSPaul Moore  * netlbl_mgmt_version - Handle a VERSION message
536d15c345fSPaul Moore  * @skb: the NETLINK buffer
537d15c345fSPaul Moore  * @info: the Generic NETLINK info block
538d15c345fSPaul Moore  *
539d15c345fSPaul Moore  * Description:
540d15c345fSPaul Moore  * Process a user generated VERSION message and respond accordingly.  Returns
541d15c345fSPaul Moore  * zero on success, negative values on failure.
542d15c345fSPaul Moore  *
543d15c345fSPaul Moore  */
544d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
545d15c345fSPaul Moore {
546d15c345fSPaul Moore 	int ret_val = -ENOMEM;
547d15c345fSPaul Moore 	struct sk_buff *ans_skb = NULL;
548fd385855SPaul Moore 	void *data;
549d15c345fSPaul Moore 
550339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
551d15c345fSPaul Moore 	if (ans_skb == NULL)
552fd385855SPaul Moore 		return -ENOMEM;
55317c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
55417c157c8SThomas Graf 				 0, NLBL_MGMT_C_VERSION);
555fd385855SPaul Moore 	if (data == NULL)
556d15c345fSPaul Moore 		goto version_failure;
557d15c345fSPaul Moore 
558fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb,
559fd385855SPaul Moore 			      NLBL_MGMT_A_VERSION,
560fd385855SPaul Moore 			      NETLBL_PROTO_VERSION);
561d15c345fSPaul Moore 	if (ret_val != 0)
562d15c345fSPaul Moore 		goto version_failure;
563d15c345fSPaul Moore 
564fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
565fd385855SPaul Moore 
56681878d27SThomas Graf 	ret_val = genlmsg_reply(ans_skb, info);
567d15c345fSPaul Moore 	if (ret_val != 0)
568d15c345fSPaul Moore 		goto version_failure;
569d15c345fSPaul Moore 	return 0;
570d15c345fSPaul Moore 
571d15c345fSPaul Moore version_failure:
572d15c345fSPaul Moore 	kfree_skb(ans_skb);
573d15c345fSPaul Moore 	return ret_val;
574d15c345fSPaul Moore }
575d15c345fSPaul Moore 
576d15c345fSPaul Moore 
577d15c345fSPaul Moore /*
578d15c345fSPaul Moore  * NetLabel Generic NETLINK Command Definitions
579d15c345fSPaul Moore  */
580d15c345fSPaul Moore 
581d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_add = {
582d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADD,
583fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
584fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
585d15c345fSPaul Moore 	.doit = netlbl_mgmt_add,
586d15c345fSPaul Moore 	.dumpit = NULL,
587d15c345fSPaul Moore };
588d15c345fSPaul Moore 
589d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_remove = {
590d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVE,
591fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
592fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
593d15c345fSPaul Moore 	.doit = netlbl_mgmt_remove,
594d15c345fSPaul Moore 	.dumpit = NULL,
595d15c345fSPaul Moore };
596d15c345fSPaul Moore 
597fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listall = {
598fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_LISTALL,
599d15c345fSPaul Moore 	.flags = 0,
600fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
601fd385855SPaul Moore 	.doit = NULL,
602fd385855SPaul Moore 	.dumpit = netlbl_mgmt_listall,
603d15c345fSPaul Moore };
604d15c345fSPaul Moore 
605d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_adddef = {
606d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADDDEF,
607fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
608fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
609d15c345fSPaul Moore 	.doit = netlbl_mgmt_adddef,
610d15c345fSPaul Moore 	.dumpit = NULL,
611d15c345fSPaul Moore };
612d15c345fSPaul Moore 
613d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_removedef = {
614d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVEDEF,
615fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
616fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
617d15c345fSPaul Moore 	.doit = netlbl_mgmt_removedef,
618d15c345fSPaul Moore 	.dumpit = NULL,
619d15c345fSPaul Moore };
620d15c345fSPaul Moore 
621d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listdef = {
622d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_LISTDEF,
623d15c345fSPaul Moore 	.flags = 0,
624fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
625d15c345fSPaul Moore 	.doit = netlbl_mgmt_listdef,
626d15c345fSPaul Moore 	.dumpit = NULL,
627d15c345fSPaul Moore };
628d15c345fSPaul Moore 
629fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_protocols = {
630fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_PROTOCOLS,
631d15c345fSPaul Moore 	.flags = 0,
632fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
633fd385855SPaul Moore 	.doit = NULL,
634fd385855SPaul Moore 	.dumpit = netlbl_mgmt_protocols,
635d15c345fSPaul Moore };
636d15c345fSPaul Moore 
637d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_version = {
638d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_VERSION,
639d15c345fSPaul Moore 	.flags = 0,
640fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
641d15c345fSPaul Moore 	.doit = netlbl_mgmt_version,
642d15c345fSPaul Moore 	.dumpit = NULL,
643d15c345fSPaul Moore };
644d15c345fSPaul Moore 
645d15c345fSPaul Moore /*
646d15c345fSPaul Moore  * NetLabel Generic NETLINK Protocol Functions
647d15c345fSPaul Moore  */
648d15c345fSPaul Moore 
649d15c345fSPaul Moore /**
650d15c345fSPaul Moore  * netlbl_mgmt_genl_init - Register the NetLabel management component
651d15c345fSPaul Moore  *
652d15c345fSPaul Moore  * Description:
653d15c345fSPaul Moore  * Register the NetLabel management component with the Generic NETLINK
654d15c345fSPaul Moore  * mechanism.  Returns zero on success, negative values on failure.
655d15c345fSPaul Moore  *
656d15c345fSPaul Moore  */
657d15c345fSPaul Moore int netlbl_mgmt_genl_init(void)
658d15c345fSPaul Moore {
659d15c345fSPaul Moore 	int ret_val;
660d15c345fSPaul Moore 
661d15c345fSPaul Moore 	ret_val = genl_register_family(&netlbl_mgmt_gnl_family);
662d15c345fSPaul Moore 	if (ret_val != 0)
663d15c345fSPaul Moore 		return ret_val;
664d15c345fSPaul Moore 
665d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
666d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_add);
667d15c345fSPaul Moore 	if (ret_val != 0)
668d15c345fSPaul Moore 		return ret_val;
669d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
670d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_remove);
671d15c345fSPaul Moore 	if (ret_val != 0)
672d15c345fSPaul Moore 		return ret_val;
673d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
674fd385855SPaul Moore 				    &netlbl_mgmt_genl_c_listall);
675d15c345fSPaul Moore 	if (ret_val != 0)
676d15c345fSPaul Moore 		return ret_val;
677d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
678d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_adddef);
679d15c345fSPaul Moore 	if (ret_val != 0)
680d15c345fSPaul Moore 		return ret_val;
681d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
682d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_removedef);
683d15c345fSPaul Moore 	if (ret_val != 0)
684d15c345fSPaul Moore 		return ret_val;
685d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
686d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_listdef);
687d15c345fSPaul Moore 	if (ret_val != 0)
688d15c345fSPaul Moore 		return ret_val;
689d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
690fd385855SPaul Moore 				    &netlbl_mgmt_genl_c_protocols);
691d15c345fSPaul Moore 	if (ret_val != 0)
692d15c345fSPaul Moore 		return ret_val;
693d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
694d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_version);
695d15c345fSPaul Moore 	if (ret_val != 0)
696d15c345fSPaul Moore 		return ret_val;
697d15c345fSPaul Moore 
698d15c345fSPaul Moore 	return 0;
699d15c345fSPaul Moore }
700