Branch data Line data Source code
1 : : /*
2 : : * NetLabel Management Support
3 : : *
4 : : * This file defines the management functions for the NetLabel system. The
5 : : * NetLabel system manages static and dynamic label mappings for network
6 : : * protocols such as CIPSO and RIPSO.
7 : : *
8 : : * Author: Paul Moore <paul@paul-moore.com>
9 : : *
10 : : */
11 : :
12 : : /*
13 : : * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14 : : *
15 : : * This program is free software; you can redistribute it and/or modify
16 : : * it under the terms of the GNU General Public License as published by
17 : : * the Free Software Foundation; either version 2 of the License, or
18 : : * (at your option) any later version.
19 : : *
20 : : * This program is distributed in the hope that it will be useful,
21 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
23 : : * the GNU General Public License for more details.
24 : : *
25 : : * You should have received a copy of the GNU General Public License
26 : : * along with this program; if not, write to the Free Software
27 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 : : *
29 : : */
30 : :
31 : : #include <linux/types.h>
32 : : #include <linux/socket.h>
33 : : #include <linux/string.h>
34 : : #include <linux/skbuff.h>
35 : : #include <linux/in.h>
36 : : #include <linux/in6.h>
37 : : #include <linux/slab.h>
38 : : #include <net/sock.h>
39 : : #include <net/netlink.h>
40 : : #include <net/genetlink.h>
41 : : #include <net/ip.h>
42 : : #include <net/ipv6.h>
43 : : #include <net/netlabel.h>
44 : : #include <net/cipso_ipv4.h>
45 : : #include <linux/atomic.h>
46 : :
47 : : #include "netlabel_domainhash.h"
48 : : #include "netlabel_user.h"
49 : : #include "netlabel_mgmt.h"
50 : :
51 : : /* NetLabel configured protocol counter */
52 : : atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
53 : :
54 : : /* Argument struct for netlbl_domhsh_walk() */
55 : : struct netlbl_domhsh_walk_arg {
56 : : struct netlink_callback *nl_cb;
57 : : struct sk_buff *skb;
58 : : u32 seq;
59 : : };
60 : :
61 : : /* NetLabel Generic NETLINK CIPSOv4 family */
62 : : static struct genl_family netlbl_mgmt_gnl_family = {
63 : : .id = GENL_ID_GENERATE,
64 : : .hdrsize = 0,
65 : : .name = NETLBL_NLTYPE_MGMT_NAME,
66 : : .version = NETLBL_PROTO_VERSION,
67 : : .maxattr = NLBL_MGMT_A_MAX,
68 : : };
69 : :
70 : : /* NetLabel Netlink attribute policy */
71 : : static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
72 : : [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
73 : : [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
74 : : [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
75 : : [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
76 : : };
77 : :
78 : : /*
79 : : * Helper Functions
80 : : */
81 : :
82 : : /**
83 : : * netlbl_mgmt_add - Handle an ADD message
84 : : * @info: the Generic NETLINK info block
85 : : * @audit_info: NetLabel audit information
86 : : *
87 : : * Description:
88 : : * Helper function for the ADD and ADDDEF messages to add the domain mappings
89 : : * from the message to the hash table. See netlabel.h for a description of the
90 : : * message format. Returns zero on success, negative values on failure.
91 : : *
92 : : */
93 : 0 : static int netlbl_mgmt_add_common(struct genl_info *info,
94 : : struct netlbl_audit *audit_info)
95 : : {
96 : : int ret_val = -EINVAL;
97 : : struct netlbl_dom_map *entry = NULL;
98 : : struct netlbl_domaddr_map *addrmap = NULL;
99 : : struct cipso_v4_doi *cipsov4 = NULL;
100 : : u32 tmp_val;
101 : :
102 : : entry = kzalloc(sizeof(*entry), GFP_KERNEL);
103 [ # # ]: 0 : if (entry == NULL) {
104 : : ret_val = -ENOMEM;
105 : : goto add_failure;
106 : : }
107 : 0 : entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
108 [ # # ]: 0 : if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
109 : 0 : size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
110 : 0 : entry->domain = kmalloc(tmp_size, GFP_KERNEL);
111 [ # # ]: 0 : if (entry->domain == NULL) {
112 : : ret_val = -ENOMEM;
113 : : goto add_failure;
114 : : }
115 : 0 : nla_strlcpy(entry->domain,
116 : 0 : info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
117 : : }
118 : :
119 : : /* NOTE: internally we allow/use a entry->def.type value of
120 : : * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
121 : : * to pass that as a protocol value because we need to know the
122 : : * "real" protocol */
123 : :
124 [ # # # ]: 0 : switch (entry->def.type) {
125 : : case NETLBL_NLTYPE_UNLABELED:
126 : : break;
127 : : case NETLBL_NLTYPE_CIPSOV4:
128 [ # # ]: 0 : if (!info->attrs[NLBL_MGMT_A_CV4DOI])
129 : : goto add_failure;
130 : :
131 : : tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
132 : 0 : cipsov4 = cipso_v4_doi_getdef(tmp_val);
133 [ # # ]: 0 : if (cipsov4 == NULL)
134 : : goto add_failure;
135 : 0 : entry->def.cipso = cipsov4;
136 : : break;
137 : : default:
138 : : goto add_failure;
139 : : }
140 : :
141 [ # # ]: 0 : if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
142 : : struct in_addr *addr;
143 : : struct in_addr *mask;
144 : : struct netlbl_domaddr4_map *map;
145 : :
146 : : addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
147 [ # # ]: 0 : if (addrmap == NULL) {
148 : : ret_val = -ENOMEM;
149 : : goto add_failure;
150 : : }
151 : 0 : INIT_LIST_HEAD(&addrmap->list4);
152 : 0 : INIT_LIST_HEAD(&addrmap->list6);
153 : :
154 [ # # ]: 0 : if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
155 : : sizeof(struct in_addr)) {
156 : : ret_val = -EINVAL;
157 : : goto add_failure;
158 : : }
159 [ # # ]: 0 : if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
160 : : sizeof(struct in_addr)) {
161 : : ret_val = -EINVAL;
162 : : goto add_failure;
163 : : }
164 : : addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
165 : : mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
166 : :
167 : : map = kzalloc(sizeof(*map), GFP_KERNEL);
168 [ # # ]: 0 : if (map == NULL) {
169 : : ret_val = -ENOMEM;
170 : : goto add_failure;
171 : : }
172 : 0 : map->list.addr = addr->s_addr & mask->s_addr;
173 : 0 : map->list.mask = mask->s_addr;
174 : 0 : map->list.valid = 1;
175 : 0 : map->def.type = entry->def.type;
176 [ # # ]: 0 : if (cipsov4)
177 : 0 : map->def.cipso = cipsov4;
178 : :
179 : 0 : ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
180 [ # # ]: 0 : if (ret_val != 0) {
181 : 0 : kfree(map);
182 : : goto add_failure;
183 : : }
184 : :
185 : 0 : entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
186 : 0 : entry->def.addrsel = addrmap;
187 : : #if IS_ENABLED(CONFIG_IPV6)
188 [ # # ]: 0 : } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
189 : : struct in6_addr *addr;
190 : : struct in6_addr *mask;
191 : : struct netlbl_domaddr6_map *map;
192 : :
193 : : addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
194 [ # # ]: 0 : if (addrmap == NULL) {
195 : : ret_val = -ENOMEM;
196 : : goto add_failure;
197 : : }
198 : 0 : INIT_LIST_HEAD(&addrmap->list4);
199 : 0 : INIT_LIST_HEAD(&addrmap->list6);
200 : :
201 [ # # ]: 0 : if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
202 : : sizeof(struct in6_addr)) {
203 : : ret_val = -EINVAL;
204 : : goto add_failure;
205 : : }
206 [ # # ]: 0 : if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
207 : : sizeof(struct in6_addr)) {
208 : : ret_val = -EINVAL;
209 : : goto add_failure;
210 : : }
211 : : addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
212 : : mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
213 : :
214 : : map = kzalloc(sizeof(*map), GFP_KERNEL);
215 [ # # ]: 0 : if (map == NULL) {
216 : : ret_val = -ENOMEM;
217 : : goto add_failure;
218 : : }
219 : 0 : map->list.addr = *addr;
220 : 0 : map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
221 : 0 : map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
222 : 0 : map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
223 : 0 : map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
224 : 0 : map->list.mask = *mask;
225 : 0 : map->list.valid = 1;
226 : 0 : map->def.type = entry->def.type;
227 : :
228 : 0 : ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
229 [ # # ]: 0 : if (ret_val != 0) {
230 : 0 : kfree(map);
231 : : goto add_failure;
232 : : }
233 : :
234 : 0 : entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
235 : 0 : entry->def.addrsel = addrmap;
236 : : #endif /* IPv6 */
237 : : }
238 : :
239 : 0 : ret_val = netlbl_domhsh_add(entry, audit_info);
240 [ # # ]: 0 : if (ret_val != 0)
241 : : goto add_failure;
242 : :
243 : : return 0;
244 : :
245 : : add_failure:
246 [ # # ]: 0 : if (cipsov4)
247 : 0 : cipso_v4_doi_putdef(cipsov4);
248 [ # # ]: 0 : if (entry)
249 : 0 : kfree(entry->domain);
250 : 0 : kfree(addrmap);
251 : 0 : kfree(entry);
252 : : return ret_val;
253 : : }
254 : :
255 : : /**
256 : : * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
257 : : * @skb: the NETLINK buffer
258 : : * @entry: the map entry
259 : : *
260 : : * Description:
261 : : * This function is a helper function used by the LISTALL and LISTDEF command
262 : : * handlers. The caller is responsible for ensuring that the RCU read lock
263 : : * is held. Returns zero on success, negative values on failure.
264 : : *
265 : : */
266 : 0 : static int netlbl_mgmt_listentry(struct sk_buff *skb,
267 : : struct netlbl_dom_map *entry)
268 : : {
269 : : int ret_val = 0;
270 : : struct nlattr *nla_a;
271 : : struct nlattr *nla_b;
272 : : struct netlbl_af4list *iter4;
273 : : #if IS_ENABLED(CONFIG_IPV6)
274 : : struct netlbl_af6list *iter6;
275 : : #endif
276 : :
277 [ # # ]: 0 : if (entry->domain != NULL) {
278 : : ret_val = nla_put_string(skb,
279 : : NLBL_MGMT_A_DOMAIN, entry->domain);
280 [ # # ]: 0 : if (ret_val != 0)
281 : : return ret_val;
282 : : }
283 : :
284 [ # # # # ]: 0 : switch (entry->def.type) {
285 : : case NETLBL_NLTYPE_ADDRSELECT:
286 : : nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
287 [ # # ]: 0 : if (nla_a == NULL)
288 : : return -ENOMEM;
289 : :
290 [ # # ]: 0 : netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
291 : : struct netlbl_domaddr4_map *map4;
292 : : struct in_addr addr_struct;
293 : :
294 : : nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
295 [ # # ]: 0 : if (nla_b == NULL)
296 : 0 : return -ENOMEM;
297 : :
298 : 0 : addr_struct.s_addr = iter4->addr;
299 : 0 : ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
300 : : sizeof(struct in_addr),
301 : : &addr_struct);
302 [ # # ]: 0 : if (ret_val != 0)
303 : : return ret_val;
304 : 0 : addr_struct.s_addr = iter4->mask;
305 : 0 : ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
306 : : sizeof(struct in_addr),
307 : : &addr_struct);
308 [ # # ]: 0 : if (ret_val != 0)
309 : : return ret_val;
310 : : map4 = netlbl_domhsh_addr4_entry(iter4);
311 : 0 : ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
312 : : map4->def.type);
313 [ # # ]: 0 : if (ret_val != 0)
314 : : return ret_val;
315 [ # # ]: 0 : switch (map4->def.type) {
316 : : case NETLBL_NLTYPE_CIPSOV4:
317 : 0 : ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
318 : 0 : map4->def.cipso->doi);
319 [ # # ]: 0 : if (ret_val != 0)
320 : : return ret_val;
321 : : break;
322 : : }
323 : :
324 : : nla_nest_end(skb, nla_b);
325 : : }
326 : : #if IS_ENABLED(CONFIG_IPV6)
327 [ # # ]: 0 : netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
328 : : struct netlbl_domaddr6_map *map6;
329 : :
330 : : nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
331 [ # # ]: 0 : if (nla_b == NULL)
332 : : return -ENOMEM;
333 : :
334 : 0 : ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
335 : : sizeof(struct in6_addr),
336 : 0 : &iter6->addr);
337 [ # # ]: 0 : if (ret_val != 0)
338 : : return ret_val;
339 : 0 : ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
340 : : sizeof(struct in6_addr),
341 : 0 : &iter6->mask);
342 [ # # ]: 0 : if (ret_val != 0)
343 : : return ret_val;
344 : : map6 = netlbl_domhsh_addr6_entry(iter6);
345 : 0 : ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
346 : : map6->def.type);
347 [ # # ]: 0 : if (ret_val != 0)
348 : : return ret_val;
349 : :
350 : : nla_nest_end(skb, nla_b);
351 : : }
352 : : #endif /* IPv6 */
353 : :
354 : : nla_nest_end(skb, nla_a);
355 : : break;
356 : : case NETLBL_NLTYPE_UNLABELED:
357 : : ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
358 : 0 : break;
359 : : case NETLBL_NLTYPE_CIPSOV4:
360 : : ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
361 [ # # ]: 0 : if (ret_val != 0)
362 : : return ret_val;
363 : 0 : ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
364 : 0 : entry->def.cipso->doi);
365 : 0 : break;
366 : : }
367 : :
368 : 0 : return ret_val;
369 : : }
370 : :
371 : : /*
372 : : * NetLabel Command Handlers
373 : : */
374 : :
375 : : /**
376 : : * netlbl_mgmt_add - Handle an ADD message
377 : : * @skb: the NETLINK buffer
378 : : * @info: the Generic NETLINK info block
379 : : *
380 : : * Description:
381 : : * Process a user generated ADD message and add the domains from the message
382 : : * to the hash table. See netlabel.h for a description of the message format.
383 : : * Returns zero on success, negative values on failure.
384 : : *
385 : : */
386 : 0 : static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
387 : : {
388 : : struct netlbl_audit audit_info;
389 : :
390 [ # # ][ # # ]: 0 : if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
391 [ # # ]: 0 : (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
392 [ # # ]: 0 : (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
393 [ # # ]: 0 : info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
394 [ # # ]: 0 : (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
395 [ # # ]: 0 : info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
396 : : ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
397 [ # # ]: 0 : (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
398 : 0 : ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
399 : 0 : (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
400 : : return -EINVAL;
401 : :
402 : : netlbl_netlink_auditinfo(skb, &audit_info);
403 : :
404 : 0 : return netlbl_mgmt_add_common(info, &audit_info);
405 : : }
406 : :
407 : : /**
408 : : * netlbl_mgmt_remove - Handle a REMOVE message
409 : : * @skb: the NETLINK buffer
410 : : * @info: the Generic NETLINK info block
411 : : *
412 : : * Description:
413 : : * Process a user generated REMOVE message and remove the specified domain
414 : : * mappings. Returns zero on success, negative values on failure.
415 : : *
416 : : */
417 : 0 : static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
418 : : {
419 : : char *domain;
420 : : struct netlbl_audit audit_info;
421 : :
422 [ # # ]: 0 : if (!info->attrs[NLBL_MGMT_A_DOMAIN])
423 : : return -EINVAL;
424 : :
425 : : netlbl_netlink_auditinfo(skb, &audit_info);
426 : :
427 : 0 : domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
428 : 0 : return netlbl_domhsh_remove(domain, &audit_info);
429 : : }
430 : :
431 : : /**
432 : : * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
433 : : * @entry: the domain mapping hash table entry
434 : : * @arg: the netlbl_domhsh_walk_arg structure
435 : : *
436 : : * Description:
437 : : * This function is designed to be used as a callback to the
438 : : * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
439 : : * message. Returns the size of the message on success, negative values on
440 : : * failure.
441 : : *
442 : : */
443 : 0 : static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
444 : : {
445 : : int ret_val = -ENOMEM;
446 : : struct netlbl_domhsh_walk_arg *cb_arg = arg;
447 : : void *data;
448 : :
449 : 0 : data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
450 : : cb_arg->seq, &netlbl_mgmt_gnl_family,
451 : : NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
452 [ # # ]: 0 : if (data == NULL)
453 : : goto listall_cb_failure;
454 : :
455 : 0 : ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
456 [ # # ]: 0 : if (ret_val != 0)
457 : : goto listall_cb_failure;
458 : :
459 : 0 : cb_arg->seq++;
460 : 0 : return genlmsg_end(cb_arg->skb, data);
461 : :
462 : : listall_cb_failure:
463 : 0 : genlmsg_cancel(cb_arg->skb, data);
464 : 0 : return ret_val;
465 : : }
466 : :
467 : : /**
468 : : * netlbl_mgmt_listall - Handle a LISTALL message
469 : : * @skb: the NETLINK buffer
470 : : * @cb: the NETLINK callback
471 : : *
472 : : * Description:
473 : : * Process a user generated LISTALL message and dumps the domain hash table in
474 : : * a form suitable for use in a kernel generated LISTALL message. Returns zero
475 : : * on success, negative values on failure.
476 : : *
477 : : */
478 : 0 : static int netlbl_mgmt_listall(struct sk_buff *skb,
479 : : struct netlink_callback *cb)
480 : : {
481 : : struct netlbl_domhsh_walk_arg cb_arg;
482 : 0 : u32 skip_bkt = cb->args[0];
483 : 0 : u32 skip_chain = cb->args[1];
484 : :
485 : 0 : cb_arg.nl_cb = cb;
486 : 0 : cb_arg.skb = skb;
487 : 0 : cb_arg.seq = cb->nlh->nlmsg_seq;
488 : :
489 : 0 : netlbl_domhsh_walk(&skip_bkt,
490 : : &skip_chain,
491 : : netlbl_mgmt_listall_cb,
492 : : &cb_arg);
493 : :
494 : 0 : cb->args[0] = skip_bkt;
495 : 0 : cb->args[1] = skip_chain;
496 : 0 : return skb->len;
497 : : }
498 : :
499 : : /**
500 : : * netlbl_mgmt_adddef - Handle an ADDDEF message
501 : : * @skb: the NETLINK buffer
502 : : * @info: the Generic NETLINK info block
503 : : *
504 : : * Description:
505 : : * Process a user generated ADDDEF message and respond accordingly. Returns
506 : : * zero on success, negative values on failure.
507 : : *
508 : : */
509 : 0 : static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
510 : : {
511 : : struct netlbl_audit audit_info;
512 : :
513 [ # # ][ # # ]: 0 : if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
514 [ # # ]: 0 : (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
515 [ # # ]: 0 : info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
516 [ # # ]: 0 : (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
517 [ # # ]: 0 : info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
518 : : ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
519 [ # # ]: 0 : (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
520 : 0 : ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
521 : 0 : (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
522 : : return -EINVAL;
523 : :
524 : : netlbl_netlink_auditinfo(skb, &audit_info);
525 : :
526 : 0 : return netlbl_mgmt_add_common(info, &audit_info);
527 : : }
528 : :
529 : : /**
530 : : * netlbl_mgmt_removedef - Handle a REMOVEDEF message
531 : : * @skb: the NETLINK buffer
532 : : * @info: the Generic NETLINK info block
533 : : *
534 : : * Description:
535 : : * Process a user generated REMOVEDEF message and remove the default domain
536 : : * mapping. Returns zero on success, negative values on failure.
537 : : *
538 : : */
539 : 0 : static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
540 : : {
541 : : struct netlbl_audit audit_info;
542 : :
543 : : netlbl_netlink_auditinfo(skb, &audit_info);
544 : :
545 : 0 : return netlbl_domhsh_remove_default(&audit_info);
546 : : }
547 : :
548 : : /**
549 : : * netlbl_mgmt_listdef - Handle a LISTDEF message
550 : : * @skb: the NETLINK buffer
551 : : * @info: the Generic NETLINK info block
552 : : *
553 : : * Description:
554 : : * Process a user generated LISTDEF message and dumps the default domain
555 : : * mapping in a form suitable for use in a kernel generated LISTDEF message.
556 : : * Returns zero on success, negative values on failure.
557 : : *
558 : : */
559 : 0 : static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
560 : : {
561 : : int ret_val = -ENOMEM;
562 : : struct sk_buff *ans_skb = NULL;
563 : : void *data;
564 : : struct netlbl_dom_map *entry;
565 : :
566 : : ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
567 [ # # ]: 0 : if (ans_skb == NULL)
568 : : return -ENOMEM;
569 : : data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
570 : : 0, NLBL_MGMT_C_LISTDEF);
571 [ # # ]: 0 : if (data == NULL)
572 : : goto listdef_failure;
573 : :
574 : : rcu_read_lock();
575 : 0 : entry = netlbl_domhsh_getentry(NULL);
576 [ # # ]: 0 : if (entry == NULL) {
577 : : ret_val = -ENOENT;
578 : : goto listdef_failure_lock;
579 : : }
580 : 0 : ret_val = netlbl_mgmt_listentry(ans_skb, entry);
581 : : rcu_read_unlock();
582 [ # # ]: 0 : if (ret_val != 0)
583 : : goto listdef_failure;
584 : :
585 : : genlmsg_end(ans_skb, data);
586 : 0 : return genlmsg_reply(ans_skb, info);
587 : :
588 : : listdef_failure_lock:
589 : : rcu_read_unlock();
590 : : listdef_failure:
591 : 0 : kfree_skb(ans_skb);
592 : 0 : return ret_val;
593 : : }
594 : :
595 : : /**
596 : : * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
597 : : * @skb: the skb to write to
598 : : * @cb: the NETLINK callback
599 : : * @protocol: the NetLabel protocol to use in the message
600 : : *
601 : : * Description:
602 : : * This function is to be used in conjunction with netlbl_mgmt_protocols() to
603 : : * answer a application's PROTOCOLS message. Returns the size of the message
604 : : * on success, negative values on failure.
605 : : *
606 : : */
607 : 0 : static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
608 : : struct netlink_callback *cb,
609 : : u32 protocol)
610 : : {
611 : : int ret_val = -ENOMEM;
612 : : void *data;
613 : :
614 : 0 : data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
615 : : &netlbl_mgmt_gnl_family, NLM_F_MULTI,
616 : : NLBL_MGMT_C_PROTOCOLS);
617 [ # # ]: 0 : if (data == NULL)
618 : : goto protocols_cb_failure;
619 : :
620 : : ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
621 [ # # ]: 0 : if (ret_val != 0)
622 : : goto protocols_cb_failure;
623 : :
624 : : return genlmsg_end(skb, data);
625 : :
626 : : protocols_cb_failure:
627 : : genlmsg_cancel(skb, data);
628 : : return ret_val;
629 : : }
630 : :
631 : : /**
632 : : * netlbl_mgmt_protocols - Handle a PROTOCOLS message
633 : : * @skb: the NETLINK buffer
634 : : * @cb: the NETLINK callback
635 : : *
636 : : * Description:
637 : : * Process a user generated PROTOCOLS message and respond accordingly.
638 : : *
639 : : */
640 : 0 : static int netlbl_mgmt_protocols(struct sk_buff *skb,
641 : 0 : struct netlink_callback *cb)
642 : : {
643 : 0 : u32 protos_sent = cb->args[0];
644 : :
645 [ # # ]: 0 : if (protos_sent == 0) {
646 [ # # ]: 0 : if (netlbl_mgmt_protocols_cb(skb,
647 : : cb,
648 : : NETLBL_NLTYPE_UNLABELED) < 0)
649 : : goto protocols_return;
650 : 0 : protos_sent++;
651 : : }
652 [ # # ]: 0 : if (protos_sent == 1) {
653 [ # # ]: 0 : if (netlbl_mgmt_protocols_cb(skb,
654 : : cb,
655 : : NETLBL_NLTYPE_CIPSOV4) < 0)
656 : : goto protocols_return;
657 : 0 : protos_sent++;
658 : : }
659 : :
660 : : protocols_return:
661 : 0 : cb->args[0] = protos_sent;
662 : 0 : return skb->len;
663 : : }
664 : :
665 : : /**
666 : : * netlbl_mgmt_version - Handle a VERSION message
667 : : * @skb: the NETLINK buffer
668 : : * @info: the Generic NETLINK info block
669 : : *
670 : : * Description:
671 : : * Process a user generated VERSION message and respond accordingly. Returns
672 : : * zero on success, negative values on failure.
673 : : *
674 : : */
675 : 0 : static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
676 : : {
677 : : int ret_val = -ENOMEM;
678 : : struct sk_buff *ans_skb = NULL;
679 : : void *data;
680 : :
681 : : ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
682 [ # # ]: 0 : if (ans_skb == NULL)
683 : : return -ENOMEM;
684 : : data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
685 : : 0, NLBL_MGMT_C_VERSION);
686 [ # # ]: 0 : if (data == NULL)
687 : : goto version_failure;
688 : :
689 : : ret_val = nla_put_u32(ans_skb,
690 : : NLBL_MGMT_A_VERSION,
691 : : NETLBL_PROTO_VERSION);
692 [ # # ]: 0 : if (ret_val != 0)
693 : : goto version_failure;
694 : :
695 : : genlmsg_end(ans_skb, data);
696 : 0 : return genlmsg_reply(ans_skb, info);
697 : :
698 : : version_failure:
699 : 0 : kfree_skb(ans_skb);
700 : 0 : return ret_val;
701 : : }
702 : :
703 : :
704 : : /*
705 : : * NetLabel Generic NETLINK Command Definitions
706 : : */
707 : :
708 : : static const struct genl_ops netlbl_mgmt_genl_ops[] = {
709 : : {
710 : : .cmd = NLBL_MGMT_C_ADD,
711 : : .flags = GENL_ADMIN_PERM,
712 : : .policy = netlbl_mgmt_genl_policy,
713 : : .doit = netlbl_mgmt_add,
714 : : .dumpit = NULL,
715 : : },
716 : : {
717 : : .cmd = NLBL_MGMT_C_REMOVE,
718 : : .flags = GENL_ADMIN_PERM,
719 : : .policy = netlbl_mgmt_genl_policy,
720 : : .doit = netlbl_mgmt_remove,
721 : : .dumpit = NULL,
722 : : },
723 : : {
724 : : .cmd = NLBL_MGMT_C_LISTALL,
725 : : .flags = 0,
726 : : .policy = netlbl_mgmt_genl_policy,
727 : : .doit = NULL,
728 : : .dumpit = netlbl_mgmt_listall,
729 : : },
730 : : {
731 : : .cmd = NLBL_MGMT_C_ADDDEF,
732 : : .flags = GENL_ADMIN_PERM,
733 : : .policy = netlbl_mgmt_genl_policy,
734 : : .doit = netlbl_mgmt_adddef,
735 : : .dumpit = NULL,
736 : : },
737 : : {
738 : : .cmd = NLBL_MGMT_C_REMOVEDEF,
739 : : .flags = GENL_ADMIN_PERM,
740 : : .policy = netlbl_mgmt_genl_policy,
741 : : .doit = netlbl_mgmt_removedef,
742 : : .dumpit = NULL,
743 : : },
744 : : {
745 : : .cmd = NLBL_MGMT_C_LISTDEF,
746 : : .flags = 0,
747 : : .policy = netlbl_mgmt_genl_policy,
748 : : .doit = netlbl_mgmt_listdef,
749 : : .dumpit = NULL,
750 : : },
751 : : {
752 : : .cmd = NLBL_MGMT_C_PROTOCOLS,
753 : : .flags = 0,
754 : : .policy = netlbl_mgmt_genl_policy,
755 : : .doit = NULL,
756 : : .dumpit = netlbl_mgmt_protocols,
757 : : },
758 : : {
759 : : .cmd = NLBL_MGMT_C_VERSION,
760 : : .flags = 0,
761 : : .policy = netlbl_mgmt_genl_policy,
762 : : .doit = netlbl_mgmt_version,
763 : : .dumpit = NULL,
764 : : },
765 : : };
766 : :
767 : : /*
768 : : * NetLabel Generic NETLINK Protocol Functions
769 : : */
770 : :
771 : : /**
772 : : * netlbl_mgmt_genl_init - Register the NetLabel management component
773 : : *
774 : : * Description:
775 : : * Register the NetLabel management component with the Generic NETLINK
776 : : * mechanism. Returns zero on success, negative values on failure.
777 : : *
778 : : */
779 : 0 : int __init netlbl_mgmt_genl_init(void)
780 : : {
781 : 0 : return genl_register_family_with_ops(&netlbl_mgmt_gnl_family,
782 : : netlbl_mgmt_genl_ops);
783 : : }
|