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