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