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