blob: ba0ca8d3f77d49720358da39e1988797b487e9e1 [file] [log] [blame]
Paul Moore96cb8e32006-08-03 16:48:59 -07001/*
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>
Paul Moore32f50cd2006-09-28 14:51:47 -070035#include <linux/audit.h>
Paul Moore96cb8e32006-08-03 16:48:59 -070036#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"
Paul Moore23bcdc12007-07-18 12:28:45 -040044#include "netlabel_mgmt.h"
Paul Moore96cb8e32006-08-03 16:48:59 -070045
Paul Moorefd385852006-09-25 15:56:37 -070046/* Argument struct for cipso_v4_doi_walk() */
47struct netlbl_cipsov4_doiwalk_arg {
48 struct netlink_callback *nl_cb;
49 struct sk_buff *skb;
50 u32 seq;
51};
52
Paul Moore96cb8e32006-08-03 16:48:59 -070053/* NetLabel Generic NETLINK CIPSOv4 family */
54static 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,
Paul Moorefd385852006-09-25 15:56:37 -070059 .maxattr = NLBL_CIPSOV4_A_MAX,
Paul Moore96cb8e32006-08-03 16:48:59 -070060};
61
Paul Moorefd385852006-09-25 15:56:37 -070062/* NetLabel Netlink attribute policy */
Patrick McHardyef7c79e2007-06-05 12:38:30 -070063static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
Paul Moorefd385852006-09-25 15:56:37 -070064 [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};
Paul Moore96cb8e32006-08-03 16:48:59 -070077
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 */
92static 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
Paul Moorefd385852006-09-25 15:56:37 -0700108/**
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 */
118static 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)
Thomas Graf8f4c1f92007-09-12 14:44:36 +0200133 if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
Paul Moore2a2f11c2007-01-05 15:08:22 -0500134 if (iter >= CIPSO_V4_TAG_MAXCNT)
Paul Moorefd385852006-09-25 15:56:37 -0700135 return -EINVAL;
136 doi_def->tags[iter++] = nla_get_u8(nla);
137 }
Paul Moore2a2f11c2007-01-05 15:08:22 -0500138 while (iter < CIPSO_V4_TAG_MAXCNT)
139 doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
Paul Moorefd385852006-09-25 15:56:37 -0700140
141 return 0;
142}
Paul Moore96cb8e32006-08-03 16:48:59 -0700143
144/*
145 * NetLabel Command Handlers
146 */
147
148/**
149 * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
Paul Moorefd385852006-09-25 15:56:37 -0700150 * @info: the Generic NETLINK info block
Paul Moore96cb8e32006-08-03 16:48:59 -0700151 *
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 */
Paul Moorefd385852006-09-25 15:56:37 -0700158static int netlbl_cipsov4_add_std(struct genl_info *info)
Paul Moore96cb8e32006-08-03 16:48:59 -0700159{
160 int ret_val = -EINVAL;
Paul Moore96cb8e32006-08-03 16:48:59 -0700161 struct cipso_v4_doi *doi_def = NULL;
Paul Moorefd385852006-09-25 15:56:37 -0700162 struct nlattr *nla_a;
163 struct nlattr *nla_b;
164 int nla_a_rem;
165 int nla_b_rem;
Paul Moorecaff5b6a2006-12-15 16:49:28 -0500166 u32 iter;
Paul Moore96cb8e32006-08-03 16:48:59 -0700167
Paul Moore32f50cd2006-09-28 14:51:47 -0700168 if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
Paul Moorefd385852006-09-25 15:56:37 -0700169 !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;
Paul Moore96cb8e32006-08-03 16:48:59 -0700176
177 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
Paul Moorefd385852006-09-25 15:56:37 -0700178 if (doi_def == NULL)
179 return -ENOMEM;
Paul Moore96cb8e32006-08-03 16:48:59 -0700180 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
Paul Moorefd385852006-09-25 15:56:37 -0700187 ret_val = netlbl_cipsov4_add_common(info, doi_def);
188 if (ret_val != 0)
189 goto add_std_failure;
Paul Moore1fd2a252006-12-15 16:49:27 -0500190 ret_val = -EINVAL;
Paul Moorefd385852006-09-25 15:56:37 -0700191
192 nla_for_each_nested(nla_a,
193 info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
194 nla_a_rem)
Thomas Graf8f4c1f92007-09-12 14:44:36 +0200195 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
Paul Moore1fd2a252006-12-15 16:49:27 -0500196 if (nla_validate_nested(nla_a,
197 NLBL_CIPSOV4_A_MAX,
198 netlbl_cipsov4_genl_policy) != 0)
199 goto add_std_failure;
Paul Moorefd385852006-09-25 15:56:37 -0700200 nla_for_each_nested(nla_b, nla_a, nla_b_rem)
Thomas Graf8f4c1f92007-09-12 14:44:36 +0200201 switch (nla_type(nla_b)) {
Paul Moorefd385852006-09-25 15:56:37 -0700202 case NLBL_CIPSOV4_A_MLSLVLLOC:
Paul Moore1fd2a252006-12-15 16:49:27 -0500203 if (nla_get_u32(nla_b) >
204 CIPSO_V4_MAX_LOC_LVLS)
205 goto add_std_failure;
Paul Moorefd385852006-09-25 15:56:37 -0700206 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:
Paul Moore1fd2a252006-12-15 16:49:27 -0500212 if (nla_get_u32(nla_b) >
213 CIPSO_V4_MAX_REM_LVLS)
214 goto add_std_failure;
Paul Moorefd385852006-09-25 15:56:37 -0700215 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 }
Paul Moore96cb8e32006-08-03 16:48:59 -0700221 }
Paul Moore96cb8e32006-08-03 16:48:59 -0700222 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 }
Paul Moore96cb8e32006-08-03 16:48:59 -0700229 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 }
Paul Moorecaff5b6a2006-12-15 16:49:28 -0500236 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;
Paul Moorefd385852006-09-25 15:56:37 -0700240 nla_for_each_nested(nla_a,
241 info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
242 nla_a_rem)
Thomas Graf8f4c1f92007-09-12 14:44:36 +0200243 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
Paul Moorefd385852006-09-25 15:56:37 -0700244 struct nlattr *lvl_loc;
245 struct nlattr *lvl_rem;
Paul Moore96cb8e32006-08-03 16:48:59 -0700246
Paul Moorefd385852006-09-25 15:56:37 -0700247 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 }
Paul Moore96cb8e32006-08-03 16:48:59 -0700258
Paul Moorefd385852006-09-25 15:56:37 -0700259 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)
Paul Moore96cb8e32006-08-03 16:48:59 -0700263 goto add_std_failure;
264
Paul Moorefd385852006-09-25 15:56:37 -0700265 nla_for_each_nested(nla_a,
266 info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
267 nla_a_rem)
Thomas Graf8f4c1f92007-09-12 14:44:36 +0200268 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
Paul Moorefd385852006-09-25 15:56:37 -0700269 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)
Thomas Graf8f4c1f92007-09-12 14:44:36 +0200274 switch (nla_type(nla_b)) {
Paul Moorefd385852006-09-25 15:56:37 -0700275 case NLBL_CIPSOV4_A_MLSCATLOC:
Paul Moore1fd2a252006-12-15 16:49:27 -0500276 if (nla_get_u32(nla_b) >
277 CIPSO_V4_MAX_LOC_CATS)
278 goto add_std_failure;
Paul Moorefd385852006-09-25 15:56:37 -0700279 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:
Paul Moore1fd2a252006-12-15 16:49:27 -0500285 if (nla_get_u32(nla_b) >
286 CIPSO_V4_MAX_REM_CATS)
287 goto add_std_failure;
Paul Moorefd385852006-09-25 15:56:37 -0700288 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 }
Paul Moorefd385852006-09-25 15:56:37 -0700295 doi_def->map.std->cat.local = kcalloc(
YOSHIFUJI Hideakie1a95262007-02-09 23:25:05 +0900296 doi_def->map.std->cat.local_size,
Paul Moorefd385852006-09-25 15:56:37 -0700297 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(
YOSHIFUJI Hideakie1a95262007-02-09 23:25:05 +0900304 doi_def->map.std->cat.cipso_size,
Paul Moorefd385852006-09-25 15:56:37 -0700305 sizeof(u32),
306 GFP_KERNEL);
307 if (doi_def->map.std->cat.cipso == NULL) {
308 ret_val = -ENOMEM;
309 goto add_std_failure;
310 }
Paul Moorecaff5b6a2006-12-15 16:49:28 -0500311 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;
Paul Moorefd385852006-09-25 15:56:37 -0700315 nla_for_each_nested(nla_a,
316 info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
317 nla_a_rem)
Thomas Graf8f4c1f92007-09-12 14:44:36 +0200318 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
Paul Moorefd385852006-09-25 15:56:37 -0700319 struct nlattr *cat_loc;
320 struct nlattr *cat_rem;
Paul Moore96cb8e32006-08-03 16:48:59 -0700321
Paul Moorefd385852006-09-25 15:56:37 -0700322 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[
YOSHIFUJI Hideakie1a95262007-02-09 23:25:05 +0900329 nla_get_u32(cat_loc)] =
Paul Moorefd385852006-09-25 15:56:37 -0700330 nla_get_u32(cat_rem);
331 doi_def->map.std->cat.cipso[
YOSHIFUJI Hideakie1a95262007-02-09 23:25:05 +0900332 nla_get_u32(cat_rem)] =
Paul Moorefd385852006-09-25 15:56:37 -0700333 nla_get_u32(cat_loc);
334 }
Paul Moore96cb8e32006-08-03 16:48:59 -0700335 }
336
Paul Moore96cb8e32006-08-03 16:48:59 -0700337 ret_val = cipso_v4_doi_add(doi_def);
338 if (ret_val != 0)
339 goto add_std_failure;
340 return 0;
341
342add_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
Paul Moorefd385852006-09-25 15:56:37 -0700350 * @info: the Generic NETLINK info block
Paul Moore96cb8e32006-08-03 16:48:59 -0700351 *
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 */
Paul Moorefd385852006-09-25 15:56:37 -0700358static int netlbl_cipsov4_add_pass(struct genl_info *info)
Paul Moore96cb8e32006-08-03 16:48:59 -0700359{
Paul Moorefd385852006-09-25 15:56:37 -0700360 int ret_val;
Paul Moore96cb8e32006-08-03 16:48:59 -0700361 struct cipso_v4_doi *doi_def = NULL;
Paul Moore96cb8e32006-08-03 16:48:59 -0700362
Paul Moore32f50cd2006-09-28 14:51:47 -0700363 if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
Paul Moorefd385852006-09-25 15:56:37 -0700364 return -EINVAL;
Paul Moore96cb8e32006-08-03 16:48:59 -0700365
366 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
Paul Moorefd385852006-09-25 15:56:37 -0700367 if (doi_def == NULL)
368 return -ENOMEM;
Paul Moore96cb8e32006-08-03 16:48:59 -0700369 doi_def->type = CIPSO_V4_MAP_PASS;
370
Paul Moorefd385852006-09-25 15:56:37 -0700371 ret_val = netlbl_cipsov4_add_common(info, doi_def);
372 if (ret_val != 0)
373 goto add_pass_failure;
Paul Moore96cb8e32006-08-03 16:48:59 -0700374
Paul Moore96cb8e32006-08-03 16:48:59 -0700375 ret_val = cipso_v4_doi_add(doi_def);
376 if (ret_val != 0)
377 goto add_pass_failure;
378 return 0;
379
380add_pass_failure:
Paul Moorefd385852006-09-25 15:56:37 -0700381 netlbl_cipsov4_doi_free(&doi_def->rcu);
Paul Moore96cb8e32006-08-03 16:48:59 -0700382 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 */
395static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
396
397{
398 int ret_val = -EINVAL;
Paul Moore32f50cd2006-09-28 14:51:47 -0700399 u32 type;
400 u32 doi;
401 const char *type_str = "(unknown)";
402 struct audit_buffer *audit_buf;
Paul Moore95d4e6b2006-09-29 17:05:05 -0700403 struct netlbl_audit audit_info;
Paul Moore96cb8e32006-08-03 16:48:59 -0700404
Paul Moore32f50cd2006-09-28 14:51:47 -0700405 if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
406 !info->attrs[NLBL_CIPSOV4_A_MTYPE])
Paul Moorefd385852006-09-25 15:56:37 -0700407 return -EINVAL;
Paul Moore96cb8e32006-08-03 16:48:59 -0700408
Paul Moore95d4e6b2006-09-29 17:05:05 -0700409 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
410 netlbl_netlink_auditinfo(skb, &audit_info);
411
Paul Moore32f50cd2006-09-28 14:51:47 -0700412 type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
413 switch (type) {
Paul Moore96cb8e32006-08-03 16:48:59 -0700414 case CIPSO_V4_MAP_STD:
Paul Moore32f50cd2006-09-28 14:51:47 -0700415 type_str = "std";
Paul Moorefd385852006-09-25 15:56:37 -0700416 ret_val = netlbl_cipsov4_add_std(info);
Paul Moore96cb8e32006-08-03 16:48:59 -0700417 break;
418 case CIPSO_V4_MAP_PASS:
Paul Moore32f50cd2006-09-28 14:51:47 -0700419 type_str = "pass";
Paul Moorefd385852006-09-25 15:56:37 -0700420 ret_val = netlbl_cipsov4_add_pass(info);
Paul Moore96cb8e32006-08-03 16:48:59 -0700421 break;
422 }
Paul Moore23bcdc12007-07-18 12:28:45 -0400423 if (ret_val == 0)
424 netlbl_mgmt_protocount_inc();
Paul Moore96cb8e32006-08-03 16:48:59 -0700425
Paul Moore95d4e6b2006-09-29 17:05:05 -0700426 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
427 &audit_info);
Paul Moorede646882006-11-17 17:38:55 -0500428 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 }
Paul Moore32f50cd2006-09-28 14:51:47 -0700436
Paul Moore96cb8e32006-08-03 16:48:59 -0700437 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:
Paul Moorefd385852006-09-25 15:56:37 -0700446 * 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.
Paul Moore96cb8e32006-08-03 16:48:59 -0700455 *
456 */
457static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
458{
Paul Moorefd385852006-09-25 15:56:37 -0700459 int ret_val;
460 struct sk_buff *ans_skb = NULL;
461 u32 nlsze_mult = 1;
462 void *data;
Paul Moore96cb8e32006-08-03 16:48:59 -0700463 u32 doi;
Paul Moorefd385852006-09-25 15:56:37 -0700464 struct nlattr *nla_a;
465 struct nlattr *nla_b;
466 struct cipso_v4_doi *doi_def;
467 u32 iter;
Paul Moore96cb8e32006-08-03 16:48:59 -0700468
Paul Moorefd385852006-09-25 15:56:37 -0700469 if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
470 ret_val = -EINVAL;
Paul Moore96cb8e32006-08-03 16:48:59 -0700471 goto list_failure;
Paul Moorefd385852006-09-25 15:56:37 -0700472 }
Paul Moore96cb8e32006-08-03 16:48:59 -0700473
Paul Moorefd385852006-09-25 15:56:37 -0700474list_start:
Thomas Graf339bf982006-11-10 14:10:15 -0800475 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
Paul Moore96cb8e32006-08-03 16:48:59 -0700476 if (ans_skb == NULL) {
477 ret_val = -ENOMEM;
478 goto list_failure;
479 }
Thomas Graf17c157c2006-11-14 19:46:02 -0800480 data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
481 0, NLBL_CIPSOV4_C_LIST);
Paul Moorefd385852006-09-25 15:56:37 -0700482 if (data == NULL) {
483 ret_val = -ENOMEM;
484 goto list_failure;
485 }
Paul Moore96cb8e32006-08-03 16:48:59 -0700486
Paul Moorefd385852006-09-25 15:56:37 -0700487 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
Thomas Graf81878d22006-11-14 19:45:27 -0800587 ret_val = genlmsg_reply(ans_skb, info);
Paul Moore96cb8e32006-08-03 16:48:59 -0700588 if (ret_val != 0)
589 goto list_failure;
590
591 return 0;
592
Paul Moorefd385852006-09-25 15:56:37 -0700593list_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 }
601list_failure_lock:
602 rcu_read_unlock();
Paul Moore96cb8e32006-08-03 16:48:59 -0700603list_failure:
Paul Moorefd385852006-09-25 15:56:37 -0700604 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 */
620static 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
Thomas Graf17c157c2006-11-14 19:46:02 -0800626 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);
Paul Moorefd385852006-09-25 15:56:37 -0700629 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
643listall_cb_failure:
644 genlmsg_cancel(cb_arg->skb, data);
Paul Moore96cb8e32006-08-03 16:48:59 -0700645 return ret_val;
646}
647
648/**
649 * netlbl_cipsov4_listall - Handle a LISTALL message
650 * @skb: the NETLINK buffer
Paul Moorefd385852006-09-25 15:56:37 -0700651 * @cb: the NETLINK callback
Paul Moore96cb8e32006-08-03 16:48:59 -0700652 *
653 * Description:
654 * Process a user generated LISTALL message and respond accordingly. Returns
655 * zero on success and negative values on error.
656 *
657 */
Paul Moorefd385852006-09-25 15:56:37 -0700658static int netlbl_cipsov4_listall(struct sk_buff *skb,
659 struct netlink_callback *cb)
Paul Moore96cb8e32006-08-03 16:48:59 -0700660{
Paul Moorefd385852006-09-25 15:56:37 -0700661 struct netlbl_cipsov4_doiwalk_arg cb_arg;
662 int doi_skip = cb->args[0];
Paul Moore96cb8e32006-08-03 16:48:59 -0700663
Paul Moorefd385852006-09-25 15:56:37 -0700664 cb_arg.nl_cb = cb;
665 cb_arg.skb = skb;
666 cb_arg.seq = cb->nlh->nlmsg_seq;
Paul Moore96cb8e32006-08-03 16:48:59 -0700667
Paul Moorefd385852006-09-25 15:56:37 -0700668 cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
Paul Moore96cb8e32006-08-03 16:48:59 -0700669
Paul Moorefd385852006-09-25 15:56:37 -0700670 cb->args[0] = doi_skip;
671 return skb->len;
Paul Moore96cb8e32006-08-03 16:48:59 -0700672}
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 */
684static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
685{
Paul Moorefd385852006-09-25 15:56:37 -0700686 int ret_val = -EINVAL;
Paul Moore32f50cd2006-09-28 14:51:47 -0700687 u32 doi = 0;
688 struct audit_buffer *audit_buf;
Paul Moore95d4e6b2006-09-29 17:05:05 -0700689 struct netlbl_audit audit_info;
Paul Moore96cb8e32006-08-03 16:48:59 -0700690
Paul Moore95d4e6b2006-09-29 17:05:05 -0700691 if (!info->attrs[NLBL_CIPSOV4_A_DOI])
692 return -EINVAL;
Paul Moore32f50cd2006-09-28 14:51:47 -0700693
Paul Moore95d4e6b2006-09-29 17:05:05 -0700694 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);
Paul Moore23bcdc12007-07-18 12:28:45 -0400700 if (ret_val == 0)
701 netlbl_mgmt_protocount_dec();
Paul Moore95d4e6b2006-09-29 17:05:05 -0700702
703 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
704 &audit_info);
Paul Moorede646882006-11-17 17:38:55 -0500705 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 }
Paul Moore96cb8e32006-08-03 16:48:59 -0700712
Paul Moore96cb8e32006-08-03 16:48:59 -0700713 return ret_val;
714}
715
716/*
717 * NetLabel Generic NETLINK Command Definitions
718 */
719
720static struct genl_ops netlbl_cipsov4_genl_c_add = {
721 .cmd = NLBL_CIPSOV4_C_ADD,
Paul Moorefd385852006-09-25 15:56:37 -0700722 .flags = GENL_ADMIN_PERM,
723 .policy = netlbl_cipsov4_genl_policy,
Paul Moore96cb8e32006-08-03 16:48:59 -0700724 .doit = netlbl_cipsov4_add,
725 .dumpit = NULL,
726};
727
728static struct genl_ops netlbl_cipsov4_genl_c_remove = {
729 .cmd = NLBL_CIPSOV4_C_REMOVE,
Paul Moorefd385852006-09-25 15:56:37 -0700730 .flags = GENL_ADMIN_PERM,
731 .policy = netlbl_cipsov4_genl_policy,
Paul Moore96cb8e32006-08-03 16:48:59 -0700732 .doit = netlbl_cipsov4_remove,
733 .dumpit = NULL,
734};
735
736static struct genl_ops netlbl_cipsov4_genl_c_list = {
737 .cmd = NLBL_CIPSOV4_C_LIST,
738 .flags = 0,
Paul Moorefd385852006-09-25 15:56:37 -0700739 .policy = netlbl_cipsov4_genl_policy,
Paul Moore96cb8e32006-08-03 16:48:59 -0700740 .doit = netlbl_cipsov4_list,
741 .dumpit = NULL,
742};
743
744static struct genl_ops netlbl_cipsov4_genl_c_listall = {
745 .cmd = NLBL_CIPSOV4_C_LISTALL,
746 .flags = 0,
Paul Moorefd385852006-09-25 15:56:37 -0700747 .policy = netlbl_cipsov4_genl_policy,
748 .doit = NULL,
749 .dumpit = netlbl_cipsov4_listall,
Paul Moore96cb8e32006-08-03 16:48:59 -0700750};
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 */
764int 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}