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