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 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 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 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