| #include <netinet/in.h> |
| #ifndef IPPROTO_DCCP |
| #define IPPROTO_DCCP 33 |
| #endif |
| #include <stdlib.h> |
| |
| #include "debug.h" |
| #include "context.h" |
| #include "handle.h" |
| |
| #include <sepol/policydb/policydb.h> |
| #include "port_internal.h" |
| |
| static inline int sepol2ipproto(sepol_handle_t * handle, int proto) |
| { |
| |
| switch (proto) { |
| case SEPOL_PROTO_TCP: |
| return IPPROTO_TCP; |
| case SEPOL_PROTO_UDP: |
| return IPPROTO_UDP; |
| case SEPOL_PROTO_DCCP: |
| return IPPROTO_DCCP; |
| default: |
| ERR(handle, "unsupported protocol %u", proto); |
| return STATUS_ERR; |
| } |
| } |
| |
| static inline int ipproto2sepol(sepol_handle_t * handle, int proto) |
| { |
| |
| switch (proto) { |
| case IPPROTO_TCP: |
| return SEPOL_PROTO_TCP; |
| case IPPROTO_UDP: |
| return SEPOL_PROTO_UDP; |
| case IPPROTO_DCCP: |
| return SEPOL_PROTO_DCCP; |
| default: |
| ERR(handle, "invalid protocol %u " "found in policy", proto); |
| return STATUS_ERR; |
| } |
| } |
| |
| /* Create a low level port structure from |
| * a high level representation */ |
| static int port_from_record(sepol_handle_t * handle, |
| const policydb_t * policydb, |
| ocontext_t ** port, const sepol_port_t * data) |
| { |
| |
| ocontext_t *tmp_port = NULL; |
| context_struct_t *tmp_con = NULL; |
| int tmp_proto; |
| |
| int low = sepol_port_get_low(data); |
| int high = sepol_port_get_high(data); |
| int proto = sepol_port_get_proto(data); |
| |
| tmp_port = (ocontext_t *) calloc(1, sizeof(ocontext_t)); |
| if (!tmp_port) |
| goto omem; |
| |
| /* Process protocol */ |
| tmp_proto = sepol2ipproto(handle, proto); |
| if (tmp_proto < 0) |
| goto err; |
| tmp_port->u.port.protocol = tmp_proto; |
| |
| /* Port range */ |
| tmp_port->u.port.low_port = low; |
| tmp_port->u.port.high_port = high; |
| if (tmp_port->u.port.low_port > tmp_port->u.port.high_port) { |
| ERR(handle, "low port %d exceeds high port %d", |
| tmp_port->u.port.low_port, tmp_port->u.port.high_port); |
| goto err; |
| } |
| |
| /* Context */ |
| if (context_from_record(handle, policydb, &tmp_con, |
| sepol_port_get_con(data)) < 0) |
| goto err; |
| context_cpy(&tmp_port->context[0], tmp_con); |
| context_destroy(tmp_con); |
| free(tmp_con); |
| tmp_con = NULL; |
| |
| *port = tmp_port; |
| return STATUS_SUCCESS; |
| |
| omem: |
| ERR(handle, "out of memory"); |
| |
| err: |
| if (tmp_port != NULL) { |
| context_destroy(&tmp_port->context[0]); |
| free(tmp_port); |
| } |
| context_destroy(tmp_con); |
| free(tmp_con); |
| ERR(handle, "could not create port structure for range %u:%u (%s)", |
| low, high, sepol_port_get_proto_str(proto)); |
| return STATUS_ERR; |
| } |
| |
| static int port_to_record(sepol_handle_t * handle, |
| const policydb_t * policydb, |
| ocontext_t * port, sepol_port_t ** record) |
| { |
| |
| int proto = port->u.port.protocol; |
| int low = port->u.port.low_port; |
| int high = port->u.port.high_port; |
| context_struct_t *con = &port->context[0]; |
| int rec_proto = -1; |
| |
| sepol_context_t *tmp_con = NULL; |
| sepol_port_t *tmp_record = NULL; |
| |
| if (sepol_port_create(handle, &tmp_record) < 0) |
| goto err; |
| |
| rec_proto = ipproto2sepol(handle, proto); |
| if (rec_proto < 0) |
| goto err; |
| |
| sepol_port_set_proto(tmp_record, rec_proto); |
| sepol_port_set_range(tmp_record, low, high); |
| |
| if (context_to_record(handle, policydb, con, &tmp_con) < 0) |
| goto err; |
| |
| if (sepol_port_set_con(handle, tmp_record, tmp_con) < 0) |
| goto err; |
| |
| sepol_context_free(tmp_con); |
| *record = tmp_record; |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not convert port range %u - %u (%s) " |
| "to record", low, high, sepol_port_get_proto_str(rec_proto)); |
| sepol_context_free(tmp_con); |
| sepol_port_free(tmp_record); |
| return STATUS_ERR; |
| } |
| |
| /* Return the number of ports */ |
| extern int sepol_port_count(sepol_handle_t * handle __attribute__ ((unused)), |
| const sepol_policydb_t * p, unsigned int *response) |
| { |
| |
| unsigned int count = 0; |
| ocontext_t *c, *head; |
| const policydb_t *policydb = &p->p; |
| |
| head = policydb->ocontexts[OCON_PORT]; |
| for (c = head; c != NULL; c = c->next) |
| count++; |
| |
| *response = count; |
| |
| return STATUS_SUCCESS; |
| } |
| |
| /* Check if a port exists */ |
| int sepol_port_exists(sepol_handle_t * handle, |
| const sepol_policydb_t * p, |
| const sepol_port_key_t * key, int *response) |
| { |
| |
| const policydb_t *policydb = &p->p; |
| ocontext_t *c, *head; |
| |
| int low, high, proto; |
| const char *proto_str; |
| sepol_port_key_unpack(key, &low, &high, &proto); |
| proto_str = sepol_port_get_proto_str(proto); |
| proto = sepol2ipproto(handle, proto); |
| if (proto < 0) |
| goto err; |
| |
| head = policydb->ocontexts[OCON_PORT]; |
| for (c = head; c; c = c->next) { |
| int proto2 = c->u.port.protocol; |
| int low2 = c->u.port.low_port; |
| int high2 = c->u.port.high_port; |
| |
| if (proto == proto2 && low2 == low && high2 == high) { |
| *response = 1; |
| return STATUS_SUCCESS; |
| } |
| } |
| |
| *response = 0; |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not check if port range %u - %u (%s) exists", |
| low, high, proto_str); |
| return STATUS_ERR; |
| } |
| |
| /* Query a port */ |
| int sepol_port_query(sepol_handle_t * handle, |
| const sepol_policydb_t * p, |
| const sepol_port_key_t * key, sepol_port_t ** response) |
| { |
| |
| const policydb_t *policydb = &p->p; |
| ocontext_t *c, *head; |
| |
| int low, high, proto; |
| const char *proto_str; |
| sepol_port_key_unpack(key, &low, &high, &proto); |
| proto_str = sepol_port_get_proto_str(proto); |
| proto = sepol2ipproto(handle, proto); |
| if (proto < 0) |
| goto err; |
| |
| head = policydb->ocontexts[OCON_PORT]; |
| for (c = head; c; c = c->next) { |
| int proto2 = c->u.port.protocol; |
| int low2 = c->u.port.low_port; |
| int high2 = c->u.port.high_port; |
| |
| if (proto == proto2 && low2 == low && high2 == high) { |
| if (port_to_record(handle, policydb, c, response) < 0) |
| goto err; |
| return STATUS_SUCCESS; |
| } |
| } |
| |
| *response = NULL; |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not query port range %u - %u (%s)", |
| low, high, proto_str); |
| return STATUS_ERR; |
| |
| } |
| |
| /* Load a port into policy */ |
| int sepol_port_modify(sepol_handle_t * handle, |
| sepol_policydb_t * p, |
| const sepol_port_key_t * key, const sepol_port_t * data) |
| { |
| |
| policydb_t *policydb = &p->p; |
| ocontext_t *port = NULL; |
| |
| int low, high, proto; |
| const char *proto_str; |
| |
| sepol_port_key_unpack(key, &low, &high, &proto); |
| proto_str = sepol_port_get_proto_str(proto); |
| proto = sepol2ipproto(handle, proto); |
| if (proto < 0) |
| goto err; |
| |
| if (port_from_record(handle, policydb, &port, data) < 0) |
| goto err; |
| |
| /* Attach to context list */ |
| port->next = policydb->ocontexts[OCON_PORT]; |
| policydb->ocontexts[OCON_PORT] = port; |
| |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not load port range %u - %u (%s)", |
| low, high, proto_str); |
| if (port != NULL) { |
| context_destroy(&port->context[0]); |
| free(port); |
| } |
| return STATUS_ERR; |
| } |
| |
| int sepol_port_iterate(sepol_handle_t * handle, |
| const sepol_policydb_t * p, |
| int (*fn) (const sepol_port_t * port, |
| void *fn_arg), void *arg) |
| { |
| |
| const policydb_t *policydb = &p->p; |
| ocontext_t *c, *head; |
| sepol_port_t *port = NULL; |
| |
| head = policydb->ocontexts[OCON_PORT]; |
| for (c = head; c; c = c->next) { |
| int status; |
| |
| if (port_to_record(handle, policydb, c, &port) < 0) |
| goto err; |
| |
| /* Invoke handler */ |
| status = fn(port, arg); |
| if (status < 0) |
| goto err; |
| |
| sepol_port_free(port); |
| port = NULL; |
| |
| /* Handler requested exit */ |
| if (status > 0) |
| break; |
| } |
| |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not iterate over ports"); |
| sepol_port_free(port); |
| return STATUS_ERR; |
| } |