1 /* 2 * NetLabel CIPSO/IPv4 Support 3 * 4 * This file defines the CIPSO/IPv4 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.moore@hp.com> 9 * 10 */ 11 12 /* 13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 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/audit.h> 36 #include <net/sock.h> 37 #include <net/netlink.h> 38 #include <net/genetlink.h> 39 #include <net/netlabel.h> 40 #include <net/cipso_ipv4.h> 41 42 #include "netlabel_user.h" 43 #include "netlabel_cipso_v4.h" 44 #include "netlabel_mgmt.h" 45 46 /* Argument struct for cipso_v4_doi_walk() */ 47 struct netlbl_cipsov4_doiwalk_arg { 48 struct netlink_callback *nl_cb; 49 struct sk_buff *skb; 50 u32 seq; 51 }; 52 53 /* NetLabel Generic NETLINK CIPSOv4 family */ 54 static struct genl_family netlbl_cipsov4_gnl_family = { 55 .id = GENL_ID_GENERATE, 56 .hdrsize = 0, 57 .name = NETLBL_NLTYPE_CIPSOV4_NAME, 58 .version = NETLBL_PROTO_VERSION, 59 .maxattr = NLBL_CIPSOV4_A_MAX, 60 }; 61 62 /* NetLabel Netlink attribute policy */ 63 static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = { 64 [NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 }, 65 [NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 }, 66 [NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 }, 67 [NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED }, 68 [NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 }, 69 [NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 }, 70 [NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED }, 71 [NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED }, 72 [NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 }, 73 [NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 }, 74 [NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED }, 75 [NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED }, 76 }; 77 78 /* 79 * Helper Functions 80 */ 81 82 /** 83 * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition 84 * @entry: the entry's RCU field 85 * 86 * Description: 87 * This function is designed to be used as a callback to the call_rcu() 88 * function so that the memory allocated to the DOI definition can be released 89 * safely. 90 * 91 */ 92 static void netlbl_cipsov4_doi_free(struct rcu_head *entry) 93 { 94 struct cipso_v4_doi *ptr; 95 96 ptr = container_of(entry, struct cipso_v4_doi, rcu); 97 switch (ptr->type) { 98 case CIPSO_V4_MAP_STD: 99 kfree(ptr->map.std->lvl.cipso); 100 kfree(ptr->map.std->lvl.local); 101 kfree(ptr->map.std->cat.cipso); 102 kfree(ptr->map.std->cat.local); 103 break; 104 } 105 kfree(ptr); 106 } 107 108 /** 109 * netlbl_cipsov4_add_common - Parse the common sections of a ADD message 110 * @info: the Generic NETLINK info block 111 * @doi_def: the CIPSO V4 DOI definition 112 * 113 * Description: 114 * Parse the common sections of a ADD message and fill in the related values 115 * in @doi_def. Returns zero on success, negative values on failure. 116 * 117 */ 118 static int netlbl_cipsov4_add_common(struct genl_info *info, 119 struct cipso_v4_doi *doi_def) 120 { 121 struct nlattr *nla; 122 int nla_rem; 123 u32 iter = 0; 124 125 doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); 126 127 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST], 128 NLBL_CIPSOV4_A_MAX, 129 netlbl_cipsov4_genl_policy) != 0) 130 return -EINVAL; 131 132 nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem) 133 if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) { 134 if (iter >= CIPSO_V4_TAG_MAXCNT) 135 return -EINVAL; 136 doi_def->tags[iter++] = nla_get_u8(nla); 137 } 138 while (iter < CIPSO_V4_TAG_MAXCNT) 139 doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID; 140 141 return 0; 142 } 143 144 /* 145 * NetLabel Command Handlers 146 */ 147 148 /** 149 * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition 150 * @info: the Generic NETLINK info block 151 * 152 * Description: 153 * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message 154 * and add it to the CIPSO V4 engine. Return zero on success and non-zero on 155 * error. 156 * 157 */ 158 static int netlbl_cipsov4_add_std(struct genl_info *info) 159 { 160 int ret_val = -EINVAL; 161 struct cipso_v4_doi *doi_def = NULL; 162 struct nlattr *nla_a; 163 struct nlattr *nla_b; 164 int nla_a_rem; 165 int nla_b_rem; 166 u32 iter; 167 168 if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] || 169 !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST]) 170 return -EINVAL; 171 172 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST], 173 NLBL_CIPSOV4_A_MAX, 174 netlbl_cipsov4_genl_policy) != 0) 175 return -EINVAL; 176 177 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); 178 if (doi_def == NULL) 179 return -ENOMEM; 180 doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL); 181 if (doi_def->map.std == NULL) { 182 ret_val = -ENOMEM; 183 goto add_std_failure; 184 } 185 doi_def->type = CIPSO_V4_MAP_STD; 186 187 ret_val = netlbl_cipsov4_add_common(info, doi_def); 188 if (ret_val != 0) 189 goto add_std_failure; 190 ret_val = -EINVAL; 191 192 nla_for_each_nested(nla_a, 193 info->attrs[NLBL_CIPSOV4_A_MLSLVLLST], 194 nla_a_rem) 195 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) { 196 if (nla_validate_nested(nla_a, 197 NLBL_CIPSOV4_A_MAX, 198 netlbl_cipsov4_genl_policy) != 0) 199 goto add_std_failure; 200 nla_for_each_nested(nla_b, nla_a, nla_b_rem) 201 switch (nla_type(nla_b)) { 202 case NLBL_CIPSOV4_A_MLSLVLLOC: 203 if (nla_get_u32(nla_b) > 204 CIPSO_V4_MAX_LOC_LVLS) 205 goto add_std_failure; 206 if (nla_get_u32(nla_b) >= 207 doi_def->map.std->lvl.local_size) 208 doi_def->map.std->lvl.local_size = 209 nla_get_u32(nla_b) + 1; 210 break; 211 case NLBL_CIPSOV4_A_MLSLVLREM: 212 if (nla_get_u32(nla_b) > 213 CIPSO_V4_MAX_REM_LVLS) 214 goto add_std_failure; 215 if (nla_get_u32(nla_b) >= 216 doi_def->map.std->lvl.cipso_size) 217 doi_def->map.std->lvl.cipso_size = 218 nla_get_u32(nla_b) + 1; 219 break; 220 } 221 } 222 doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size, 223 sizeof(u32), 224 GFP_KERNEL); 225 if (doi_def->map.std->lvl.local == NULL) { 226 ret_val = -ENOMEM; 227 goto add_std_failure; 228 } 229 doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size, 230 sizeof(u32), 231 GFP_KERNEL); 232 if (doi_def->map.std->lvl.cipso == NULL) { 233 ret_val = -ENOMEM; 234 goto add_std_failure; 235 } 236 for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++) 237 doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL; 238 for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++) 239 doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL; 240 nla_for_each_nested(nla_a, 241 info->attrs[NLBL_CIPSOV4_A_MLSLVLLST], 242 nla_a_rem) 243 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) { 244 struct nlattr *lvl_loc; 245 struct nlattr *lvl_rem; 246 247 lvl_loc = nla_find_nested(nla_a, 248 NLBL_CIPSOV4_A_MLSLVLLOC); 249 lvl_rem = nla_find_nested(nla_a, 250 NLBL_CIPSOV4_A_MLSLVLREM); 251 if (lvl_loc == NULL || lvl_rem == NULL) 252 goto add_std_failure; 253 doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] = 254 nla_get_u32(lvl_rem); 255 doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] = 256 nla_get_u32(lvl_loc); 257 } 258 259 if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) { 260 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST], 261 NLBL_CIPSOV4_A_MAX, 262 netlbl_cipsov4_genl_policy) != 0) 263 goto add_std_failure; 264 265 nla_for_each_nested(nla_a, 266 info->attrs[NLBL_CIPSOV4_A_MLSCATLST], 267 nla_a_rem) 268 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) { 269 if (nla_validate_nested(nla_a, 270 NLBL_CIPSOV4_A_MAX, 271 netlbl_cipsov4_genl_policy) != 0) 272 goto add_std_failure; 273 nla_for_each_nested(nla_b, nla_a, nla_b_rem) 274 switch (nla_type(nla_b)) { 275 case NLBL_CIPSOV4_A_MLSCATLOC: 276 if (nla_get_u32(nla_b) > 277 CIPSO_V4_MAX_LOC_CATS) 278 goto add_std_failure; 279 if (nla_get_u32(nla_b) >= 280 doi_def->map.std->cat.local_size) 281 doi_def->map.std->cat.local_size = 282 nla_get_u32(nla_b) + 1; 283 break; 284 case NLBL_CIPSOV4_A_MLSCATREM: 285 if (nla_get_u32(nla_b) > 286 CIPSO_V4_MAX_REM_CATS) 287 goto add_std_failure; 288 if (nla_get_u32(nla_b) >= 289 doi_def->map.std->cat.cipso_size) 290 doi_def->map.std->cat.cipso_size = 291 nla_get_u32(nla_b) + 1; 292 break; 293 } 294 } 295 doi_def->map.std->cat.local = kcalloc( 296 doi_def->map.std->cat.local_size, 297 sizeof(u32), 298 GFP_KERNEL); 299 if (doi_def->map.std->cat.local == NULL) { 300 ret_val = -ENOMEM; 301 goto add_std_failure; 302 } 303 doi_def->map.std->cat.cipso = kcalloc( 304 doi_def->map.std->cat.cipso_size, 305 sizeof(u32), 306 GFP_KERNEL); 307 if (doi_def->map.std->cat.cipso == NULL) { 308 ret_val = -ENOMEM; 309 goto add_std_failure; 310 } 311 for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++) 312 doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT; 313 for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++) 314 doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT; 315 nla_for_each_nested(nla_a, 316 info->attrs[NLBL_CIPSOV4_A_MLSCATLST], 317 nla_a_rem) 318 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) { 319 struct nlattr *cat_loc; 320 struct nlattr *cat_rem; 321 322 cat_loc = nla_find_nested(nla_a, 323 NLBL_CIPSOV4_A_MLSCATLOC); 324 cat_rem = nla_find_nested(nla_a, 325 NLBL_CIPSOV4_A_MLSCATREM); 326 if (cat_loc == NULL || cat_rem == NULL) 327 goto add_std_failure; 328 doi_def->map.std->cat.local[ 329 nla_get_u32(cat_loc)] = 330 nla_get_u32(cat_rem); 331 doi_def->map.std->cat.cipso[ 332 nla_get_u32(cat_rem)] = 333 nla_get_u32(cat_loc); 334 } 335 } 336 337 ret_val = cipso_v4_doi_add(doi_def); 338 if (ret_val != 0) 339 goto add_std_failure; 340 return 0; 341 342 add_std_failure: 343 if (doi_def) 344 netlbl_cipsov4_doi_free(&doi_def->rcu); 345 return ret_val; 346 } 347 348 /** 349 * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition 350 * @info: the Generic NETLINK info block 351 * 352 * Description: 353 * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message 354 * and add it to the CIPSO V4 engine. Return zero on success and non-zero on 355 * error. 356 * 357 */ 358 static int netlbl_cipsov4_add_pass(struct genl_info *info) 359 { 360 int ret_val; 361 struct cipso_v4_doi *doi_def = NULL; 362 363 if (!info->attrs[NLBL_CIPSOV4_A_TAGLST]) 364 return -EINVAL; 365 366 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); 367 if (doi_def == NULL) 368 return -ENOMEM; 369 doi_def->type = CIPSO_V4_MAP_PASS; 370 371 ret_val = netlbl_cipsov4_add_common(info, doi_def); 372 if (ret_val != 0) 373 goto add_pass_failure; 374 375 ret_val = cipso_v4_doi_add(doi_def); 376 if (ret_val != 0) 377 goto add_pass_failure; 378 return 0; 379 380 add_pass_failure: 381 netlbl_cipsov4_doi_free(&doi_def->rcu); 382 return ret_val; 383 } 384 385 /** 386 * netlbl_cipsov4_add - Handle an ADD message 387 * @skb: the NETLINK buffer 388 * @info: the Generic NETLINK info block 389 * 390 * Description: 391 * Create a new DOI definition based on the given ADD message and add it to the 392 * CIPSO V4 engine. Returns zero on success, negative values on failure. 393 * 394 */ 395 static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) 396 397 { 398 int ret_val = -EINVAL; 399 u32 type; 400 u32 doi; 401 const char *type_str = "(unknown)"; 402 struct audit_buffer *audit_buf; 403 struct netlbl_audit audit_info; 404 405 if (!info->attrs[NLBL_CIPSOV4_A_DOI] || 406 !info->attrs[NLBL_CIPSOV4_A_MTYPE]) 407 return -EINVAL; 408 409 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); 410 netlbl_netlink_auditinfo(skb, &audit_info); 411 412 type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); 413 switch (type) { 414 case CIPSO_V4_MAP_STD: 415 type_str = "std"; 416 ret_val = netlbl_cipsov4_add_std(info); 417 break; 418 case CIPSO_V4_MAP_PASS: 419 type_str = "pass"; 420 ret_val = netlbl_cipsov4_add_pass(info); 421 break; 422 } 423 if (ret_val == 0) 424 netlbl_mgmt_protocount_inc(); 425 426 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, 427 &audit_info); 428 if (audit_buf != NULL) { 429 audit_log_format(audit_buf, 430 " cipso_doi=%u cipso_type=%s res=%u", 431 doi, 432 type_str, 433 ret_val == 0 ? 1 : 0); 434 audit_log_end(audit_buf); 435 } 436 437 return ret_val; 438 } 439 440 /** 441 * netlbl_cipsov4_list - Handle a LIST message 442 * @skb: the NETLINK buffer 443 * @info: the Generic NETLINK info block 444 * 445 * Description: 446 * Process a user generated LIST message and respond accordingly. While the 447 * response message generated by the kernel is straightforward, determining 448 * before hand the size of the buffer to allocate is not (we have to generate 449 * the message to know the size). In order to keep this function sane what we 450 * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in 451 * that size, if we fail then we restart with a larger buffer and try again. 452 * We continue in this manner until we hit a limit of failed attempts then we 453 * give up and just send an error message. Returns zero on success and 454 * negative values on error. 455 * 456 */ 457 static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info) 458 { 459 int ret_val; 460 struct sk_buff *ans_skb = NULL; 461 u32 nlsze_mult = 1; 462 void *data; 463 u32 doi; 464 struct nlattr *nla_a; 465 struct nlattr *nla_b; 466 struct cipso_v4_doi *doi_def; 467 u32 iter; 468 469 if (!info->attrs[NLBL_CIPSOV4_A_DOI]) { 470 ret_val = -EINVAL; 471 goto list_failure; 472 } 473 474 list_start: 475 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL); 476 if (ans_skb == NULL) { 477 ret_val = -ENOMEM; 478 goto list_failure; 479 } 480 data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family, 481 0, NLBL_CIPSOV4_C_LIST); 482 if (data == NULL) { 483 ret_val = -ENOMEM; 484 goto list_failure; 485 } 486 487 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); 488 489 rcu_read_lock(); 490 doi_def = cipso_v4_doi_getdef(doi); 491 if (doi_def == NULL) { 492 ret_val = -EINVAL; 493 goto list_failure; 494 } 495 496 ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); 497 if (ret_val != 0) 498 goto list_failure_lock; 499 500 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST); 501 if (nla_a == NULL) { 502 ret_val = -ENOMEM; 503 goto list_failure_lock; 504 } 505 for (iter = 0; 506 iter < CIPSO_V4_TAG_MAXCNT && 507 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID; 508 iter++) { 509 ret_val = nla_put_u8(ans_skb, 510 NLBL_CIPSOV4_A_TAG, 511 doi_def->tags[iter]); 512 if (ret_val != 0) 513 goto list_failure_lock; 514 } 515 nla_nest_end(ans_skb, nla_a); 516 517 switch (doi_def->type) { 518 case CIPSO_V4_MAP_STD: 519 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); 520 if (nla_a == NULL) { 521 ret_val = -ENOMEM; 522 goto list_failure_lock; 523 } 524 for (iter = 0; 525 iter < doi_def->map.std->lvl.local_size; 526 iter++) { 527 if (doi_def->map.std->lvl.local[iter] == 528 CIPSO_V4_INV_LVL) 529 continue; 530 531 nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL); 532 if (nla_b == NULL) { 533 ret_val = -ENOMEM; 534 goto list_retry; 535 } 536 ret_val = nla_put_u32(ans_skb, 537 NLBL_CIPSOV4_A_MLSLVLLOC, 538 iter); 539 if (ret_val != 0) 540 goto list_retry; 541 ret_val = nla_put_u32(ans_skb, 542 NLBL_CIPSOV4_A_MLSLVLREM, 543 doi_def->map.std->lvl.local[iter]); 544 if (ret_val != 0) 545 goto list_retry; 546 nla_nest_end(ans_skb, nla_b); 547 } 548 nla_nest_end(ans_skb, nla_a); 549 550 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST); 551 if (nla_a == NULL) { 552 ret_val = -ENOMEM; 553 goto list_retry; 554 } 555 for (iter = 0; 556 iter < doi_def->map.std->cat.local_size; 557 iter++) { 558 if (doi_def->map.std->cat.local[iter] == 559 CIPSO_V4_INV_CAT) 560 continue; 561 562 nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT); 563 if (nla_b == NULL) { 564 ret_val = -ENOMEM; 565 goto list_retry; 566 } 567 ret_val = nla_put_u32(ans_skb, 568 NLBL_CIPSOV4_A_MLSCATLOC, 569 iter); 570 if (ret_val != 0) 571 goto list_retry; 572 ret_val = nla_put_u32(ans_skb, 573 NLBL_CIPSOV4_A_MLSCATREM, 574 doi_def->map.std->cat.local[iter]); 575 if (ret_val != 0) 576 goto list_retry; 577 nla_nest_end(ans_skb, nla_b); 578 } 579 nla_nest_end(ans_skb, nla_a); 580 581 break; 582 } 583 rcu_read_unlock(); 584 585 genlmsg_end(ans_skb, data); 586 587 ret_val = genlmsg_reply(ans_skb, info); 588 if (ret_val != 0) 589 goto list_failure; 590 591 return 0; 592 593 list_retry: 594 /* XXX - this limit is a guesstimate */ 595 if (nlsze_mult < 4) { 596 rcu_read_unlock(); 597 kfree_skb(ans_skb); 598 nlsze_mult++; 599 goto list_start; 600 } 601 list_failure_lock: 602 rcu_read_unlock(); 603 list_failure: 604 kfree_skb(ans_skb); 605 return ret_val; 606 } 607 608 /** 609 * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL 610 * @doi_def: the CIPSOv4 DOI definition 611 * @arg: the netlbl_cipsov4_doiwalk_arg structure 612 * 613 * Description: 614 * This function is designed to be used as a callback to the 615 * cipso_v4_doi_walk() function for use in generating a response for a LISTALL 616 * message. Returns the size of the message on success, negative values on 617 * failure. 618 * 619 */ 620 static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg) 621 { 622 int ret_val = -ENOMEM; 623 struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg; 624 void *data; 625 626 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid, 627 cb_arg->seq, &netlbl_cipsov4_gnl_family, 628 NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL); 629 if (data == NULL) 630 goto listall_cb_failure; 631 632 ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi); 633 if (ret_val != 0) 634 goto listall_cb_failure; 635 ret_val = nla_put_u32(cb_arg->skb, 636 NLBL_CIPSOV4_A_MTYPE, 637 doi_def->type); 638 if (ret_val != 0) 639 goto listall_cb_failure; 640 641 return genlmsg_end(cb_arg->skb, data); 642 643 listall_cb_failure: 644 genlmsg_cancel(cb_arg->skb, data); 645 return ret_val; 646 } 647 648 /** 649 * netlbl_cipsov4_listall - Handle a LISTALL message 650 * @skb: the NETLINK buffer 651 * @cb: the NETLINK callback 652 * 653 * Description: 654 * Process a user generated LISTALL message and respond accordingly. Returns 655 * zero on success and negative values on error. 656 * 657 */ 658 static int netlbl_cipsov4_listall(struct sk_buff *skb, 659 struct netlink_callback *cb) 660 { 661 struct netlbl_cipsov4_doiwalk_arg cb_arg; 662 int doi_skip = cb->args[0]; 663 664 cb_arg.nl_cb = cb; 665 cb_arg.skb = skb; 666 cb_arg.seq = cb->nlh->nlmsg_seq; 667 668 cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg); 669 670 cb->args[0] = doi_skip; 671 return skb->len; 672 } 673 674 /** 675 * netlbl_cipsov4_remove - Handle a REMOVE message 676 * @skb: the NETLINK buffer 677 * @info: the Generic NETLINK info block 678 * 679 * Description: 680 * Process a user generated REMOVE message and respond accordingly. Returns 681 * zero on success, negative values on failure. 682 * 683 */ 684 static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) 685 { 686 int ret_val = -EINVAL; 687 u32 doi = 0; 688 struct audit_buffer *audit_buf; 689 struct netlbl_audit audit_info; 690 691 if (!info->attrs[NLBL_CIPSOV4_A_DOI]) 692 return -EINVAL; 693 694 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); 695 netlbl_netlink_auditinfo(skb, &audit_info); 696 697 ret_val = cipso_v4_doi_remove(doi, 698 &audit_info, 699 netlbl_cipsov4_doi_free); 700 if (ret_val == 0) 701 netlbl_mgmt_protocount_dec(); 702 703 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, 704 &audit_info); 705 if (audit_buf != NULL) { 706 audit_log_format(audit_buf, 707 " cipso_doi=%u res=%u", 708 doi, 709 ret_val == 0 ? 1 : 0); 710 audit_log_end(audit_buf); 711 } 712 713 return ret_val; 714 } 715 716 /* 717 * NetLabel Generic NETLINK Command Definitions 718 */ 719 720 static struct genl_ops netlbl_cipsov4_genl_c_add = { 721 .cmd = NLBL_CIPSOV4_C_ADD, 722 .flags = GENL_ADMIN_PERM, 723 .policy = netlbl_cipsov4_genl_policy, 724 .doit = netlbl_cipsov4_add, 725 .dumpit = NULL, 726 }; 727 728 static struct genl_ops netlbl_cipsov4_genl_c_remove = { 729 .cmd = NLBL_CIPSOV4_C_REMOVE, 730 .flags = GENL_ADMIN_PERM, 731 .policy = netlbl_cipsov4_genl_policy, 732 .doit = netlbl_cipsov4_remove, 733 .dumpit = NULL, 734 }; 735 736 static struct genl_ops netlbl_cipsov4_genl_c_list = { 737 .cmd = NLBL_CIPSOV4_C_LIST, 738 .flags = 0, 739 .policy = netlbl_cipsov4_genl_policy, 740 .doit = netlbl_cipsov4_list, 741 .dumpit = NULL, 742 }; 743 744 static struct genl_ops netlbl_cipsov4_genl_c_listall = { 745 .cmd = NLBL_CIPSOV4_C_LISTALL, 746 .flags = 0, 747 .policy = netlbl_cipsov4_genl_policy, 748 .doit = NULL, 749 .dumpit = netlbl_cipsov4_listall, 750 }; 751 752 /* 753 * NetLabel Generic NETLINK Protocol Functions 754 */ 755 756 /** 757 * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component 758 * 759 * Description: 760 * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK 761 * mechanism. Returns zero on success, negative values on failure. 762 * 763 */ 764 int netlbl_cipsov4_genl_init(void) 765 { 766 int ret_val; 767 768 ret_val = genl_register_family(&netlbl_cipsov4_gnl_family); 769 if (ret_val != 0) 770 return ret_val; 771 772 ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, 773 &netlbl_cipsov4_genl_c_add); 774 if (ret_val != 0) 775 return ret_val; 776 ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, 777 &netlbl_cipsov4_genl_c_remove); 778 if (ret_val != 0) 779 return ret_val; 780 ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, 781 &netlbl_cipsov4_genl_c_list); 782 if (ret_val != 0) 783 return ret_val; 784 ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, 785 &netlbl_cipsov4_genl_c_listall); 786 if (ret_val != 0) 787 return ret_val; 788 789 return 0; 790 } 791