1 #include <netinet/in.h>
2 #ifndef IPPROTO_DCCP
3 #define IPPROTO_DCCP 33
4 #endif
5 #ifndef IPPROTO_SCTP
6 #define IPPROTO_SCTP 132
7 #endif
8 #include <stdlib.h>
9
10 #include "debug.h"
11 #include "context.h"
12 #include "handle.h"
13
14 #include <sepol/policydb/policydb.h>
15 #include "port_internal.h"
16
sepol2ipproto(sepol_handle_t * handle,int proto)17 static inline int sepol2ipproto(sepol_handle_t * handle, int proto)
18 {
19
20 switch (proto) {
21 case SEPOL_PROTO_TCP:
22 return IPPROTO_TCP;
23 case SEPOL_PROTO_UDP:
24 return IPPROTO_UDP;
25 case SEPOL_PROTO_DCCP:
26 return IPPROTO_DCCP;
27 case SEPOL_PROTO_SCTP:
28 return IPPROTO_SCTP;
29 default:
30 ERR(handle, "unsupported protocol %u", proto);
31 return STATUS_ERR;
32 }
33 }
34
ipproto2sepol(sepol_handle_t * handle,int proto)35 static inline int ipproto2sepol(sepol_handle_t * handle, int proto)
36 {
37
38 switch (proto) {
39 case IPPROTO_TCP:
40 return SEPOL_PROTO_TCP;
41 case IPPROTO_UDP:
42 return SEPOL_PROTO_UDP;
43 case IPPROTO_DCCP:
44 return SEPOL_PROTO_DCCP;
45 case IPPROTO_SCTP:
46 return SEPOL_PROTO_SCTP;
47 default:
48 ERR(handle, "invalid protocol %u " "found in policy", proto);
49 return STATUS_ERR;
50 }
51 }
52
53 /* Create a low level port structure from
54 * a high level representation */
port_from_record(sepol_handle_t * handle,const policydb_t * policydb,ocontext_t ** port,const sepol_port_t * data)55 static int port_from_record(sepol_handle_t * handle,
56 const policydb_t * policydb,
57 ocontext_t ** port, const sepol_port_t * data)
58 {
59
60 ocontext_t *tmp_port = NULL;
61 context_struct_t *tmp_con = NULL;
62 int tmp_proto;
63
64 int low = sepol_port_get_low(data);
65 int high = sepol_port_get_high(data);
66 int proto = sepol_port_get_proto(data);
67
68 tmp_port = (ocontext_t *) calloc(1, sizeof(ocontext_t));
69 if (!tmp_port)
70 goto omem;
71
72 /* Process protocol */
73 tmp_proto = sepol2ipproto(handle, proto);
74 if (tmp_proto < 0)
75 goto err;
76 tmp_port->u.port.protocol = tmp_proto;
77
78 /* Port range */
79 tmp_port->u.port.low_port = low;
80 tmp_port->u.port.high_port = high;
81 if (tmp_port->u.port.low_port > tmp_port->u.port.high_port) {
82 ERR(handle, "low port %d exceeds high port %d",
83 tmp_port->u.port.low_port, tmp_port->u.port.high_port);
84 goto err;
85 }
86
87 /* Context */
88 if (context_from_record(handle, policydb, &tmp_con,
89 sepol_port_get_con(data)) < 0)
90 goto err;
91 context_cpy(&tmp_port->context[0], tmp_con);
92 context_destroy(tmp_con);
93 free(tmp_con);
94 tmp_con = NULL;
95
96 *port = tmp_port;
97 return STATUS_SUCCESS;
98
99 omem:
100 ERR(handle, "out of memory");
101
102 err:
103 if (tmp_port != NULL) {
104 context_destroy(&tmp_port->context[0]);
105 free(tmp_port);
106 }
107 context_destroy(tmp_con);
108 free(tmp_con);
109 ERR(handle, "could not create port structure for range %u:%u (%s)",
110 low, high, sepol_port_get_proto_str(proto));
111 return STATUS_ERR;
112 }
113
port_to_record(sepol_handle_t * handle,const policydb_t * policydb,ocontext_t * port,sepol_port_t ** record)114 static int port_to_record(sepol_handle_t * handle,
115 const policydb_t * policydb,
116 ocontext_t * port, sepol_port_t ** record)
117 {
118
119 int proto = port->u.port.protocol;
120 int low = port->u.port.low_port;
121 int high = port->u.port.high_port;
122 context_struct_t *con = &port->context[0];
123 int rec_proto = -1;
124
125 sepol_context_t *tmp_con = NULL;
126 sepol_port_t *tmp_record = NULL;
127
128 if (sepol_port_create(handle, &tmp_record) < 0)
129 goto err;
130
131 rec_proto = ipproto2sepol(handle, proto);
132 if (rec_proto < 0)
133 goto err;
134
135 sepol_port_set_proto(tmp_record, rec_proto);
136 sepol_port_set_range(tmp_record, low, high);
137
138 if (context_to_record(handle, policydb, con, &tmp_con) < 0)
139 goto err;
140
141 if (sepol_port_set_con(handle, tmp_record, tmp_con) < 0)
142 goto err;
143
144 sepol_context_free(tmp_con);
145 *record = tmp_record;
146 return STATUS_SUCCESS;
147
148 err:
149 ERR(handle, "could not convert port range %u - %u (%s) "
150 "to record", low, high, sepol_port_get_proto_str(rec_proto));
151 sepol_context_free(tmp_con);
152 sepol_port_free(tmp_record);
153 return STATUS_ERR;
154 }
155
156 /* Return the number of ports */
sepol_port_count(sepol_handle_t * handle,const sepol_policydb_t * p,unsigned int * response)157 extern int sepol_port_count(sepol_handle_t * handle __attribute__ ((unused)),
158 const sepol_policydb_t * p, unsigned int *response)
159 {
160
161 unsigned int count = 0;
162 ocontext_t *c, *head;
163 const policydb_t *policydb = &p->p;
164
165 head = policydb->ocontexts[OCON_PORT];
166 for (c = head; c != NULL; c = c->next)
167 count++;
168
169 *response = count;
170
171 return STATUS_SUCCESS;
172 }
173
174 /* Check if a port exists */
sepol_port_exists(sepol_handle_t * handle,const sepol_policydb_t * p,const sepol_port_key_t * key,int * response)175 int sepol_port_exists(sepol_handle_t * handle,
176 const sepol_policydb_t * p,
177 const sepol_port_key_t * key, int *response)
178 {
179
180 const policydb_t *policydb = &p->p;
181 ocontext_t *c, *head;
182
183 int low, high, proto;
184 const char *proto_str;
185 sepol_port_key_unpack(key, &low, &high, &proto);
186 proto_str = sepol_port_get_proto_str(proto);
187 proto = sepol2ipproto(handle, proto);
188 if (proto < 0)
189 goto err;
190
191 head = policydb->ocontexts[OCON_PORT];
192 for (c = head; c; c = c->next) {
193 int proto2 = c->u.port.protocol;
194 int low2 = c->u.port.low_port;
195 int high2 = c->u.port.high_port;
196
197 if (proto == proto2 && low2 == low && high2 == high) {
198 *response = 1;
199 return STATUS_SUCCESS;
200 }
201 }
202
203 *response = 0;
204 return STATUS_SUCCESS;
205
206 err:
207 ERR(handle, "could not check if port range %u - %u (%s) exists",
208 low, high, proto_str);
209 return STATUS_ERR;
210 }
211
212 /* Query a port */
sepol_port_query(sepol_handle_t * handle,const sepol_policydb_t * p,const sepol_port_key_t * key,sepol_port_t ** response)213 int sepol_port_query(sepol_handle_t * handle,
214 const sepol_policydb_t * p,
215 const sepol_port_key_t * key, sepol_port_t ** response)
216 {
217
218 const policydb_t *policydb = &p->p;
219 ocontext_t *c, *head;
220
221 int low, high, proto;
222 const char *proto_str;
223 sepol_port_key_unpack(key, &low, &high, &proto);
224 proto_str = sepol_port_get_proto_str(proto);
225 proto = sepol2ipproto(handle, proto);
226 if (proto < 0)
227 goto err;
228
229 head = policydb->ocontexts[OCON_PORT];
230 for (c = head; c; c = c->next) {
231 int proto2 = c->u.port.protocol;
232 int low2 = c->u.port.low_port;
233 int high2 = c->u.port.high_port;
234
235 if (proto == proto2 && low2 == low && high2 == high) {
236 if (port_to_record(handle, policydb, c, response) < 0)
237 goto err;
238 return STATUS_SUCCESS;
239 }
240 }
241
242 *response = NULL;
243 return STATUS_SUCCESS;
244
245 err:
246 ERR(handle, "could not query port range %u - %u (%s)",
247 low, high, proto_str);
248 return STATUS_ERR;
249
250 }
251
252 /* Load a port into policy */
sepol_port_modify(sepol_handle_t * handle,sepol_policydb_t * p,const sepol_port_key_t * key,const sepol_port_t * data)253 int sepol_port_modify(sepol_handle_t * handle,
254 sepol_policydb_t * p,
255 const sepol_port_key_t * key, const sepol_port_t * data)
256 {
257
258 policydb_t *policydb = &p->p;
259 ocontext_t *port = NULL;
260
261 int low, high, proto;
262 const char *proto_str;
263
264 sepol_port_key_unpack(key, &low, &high, &proto);
265 proto_str = sepol_port_get_proto_str(proto);
266 proto = sepol2ipproto(handle, proto);
267 if (proto < 0)
268 goto err;
269
270 if (port_from_record(handle, policydb, &port, data) < 0)
271 goto err;
272
273 /* Attach to context list */
274 port->next = policydb->ocontexts[OCON_PORT];
275 policydb->ocontexts[OCON_PORT] = port;
276
277 return STATUS_SUCCESS;
278
279 err:
280 ERR(handle, "could not load port range %u - %u (%s)",
281 low, high, proto_str);
282 if (port != NULL) {
283 context_destroy(&port->context[0]);
284 free(port);
285 }
286 return STATUS_ERR;
287 }
288
sepol_port_iterate(sepol_handle_t * handle,const sepol_policydb_t * p,int (* fn)(const sepol_port_t * port,void * fn_arg),void * arg)289 int sepol_port_iterate(sepol_handle_t * handle,
290 const sepol_policydb_t * p,
291 int (*fn) (const sepol_port_t * port,
292 void *fn_arg), void *arg)
293 {
294
295 const policydb_t *policydb = &p->p;
296 ocontext_t *c, *head;
297 sepol_port_t *port = NULL;
298
299 head = policydb->ocontexts[OCON_PORT];
300 for (c = head; c; c = c->next) {
301 int status;
302
303 if (port_to_record(handle, policydb, c, &port) < 0)
304 goto err;
305
306 /* Invoke handler */
307 status = fn(port, arg);
308 if (status < 0)
309 goto err;
310
311 sepol_port_free(port);
312 port = NULL;
313
314 /* Handler requested exit */
315 if (status > 0)
316 break;
317 }
318
319 return STATUS_SUCCESS;
320
321 err:
322 ERR(handle, "could not iterate over ports");
323 sepol_port_free(port);
324 return STATUS_ERR;
325 }
326