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