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 17static 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 35static 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 */ 55static 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 114static 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 */ 157extern 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 */ 175int 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 */ 213int 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 */ 253int 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 289int 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