| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <stdlib.h> |
| |
| #include "debug.h" |
| #include "context.h" |
| #include "handle.h" |
| |
| #include <sepol/policydb/policydb.h> |
| #include "node_internal.h" |
| |
| /* Create a low level node structure from |
| * a high level representation */ |
| static int node_from_record(sepol_handle_t * handle, |
| const policydb_t * policydb, |
| ocontext_t ** node, const sepol_node_t * data) |
| { |
| |
| ocontext_t *tmp_node = NULL; |
| context_struct_t *tmp_con = NULL; |
| char *addr_buf = NULL, *mask_buf = NULL; |
| size_t addr_bsize, mask_bsize; |
| int proto; |
| |
| tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t)); |
| if (!tmp_node) |
| goto omem; |
| |
| /* Address and netmask */ |
| if (sepol_node_get_addr_bytes(handle, data, &addr_buf, &addr_bsize) < 0) |
| goto err; |
| if (sepol_node_get_mask_bytes(handle, data, &mask_buf, &mask_bsize) < 0) |
| goto err; |
| |
| proto = sepol_node_get_proto(data); |
| |
| switch (proto) { |
| case SEPOL_PROTO_IP4: |
| memcpy(&tmp_node->u.node.addr, addr_buf, addr_bsize); |
| memcpy(&tmp_node->u.node.mask, mask_buf, mask_bsize); |
| break; |
| case SEPOL_PROTO_IP6: |
| memcpy(tmp_node->u.node6.addr, addr_buf, addr_bsize); |
| memcpy(tmp_node->u.node6.mask, mask_buf, mask_bsize); |
| break; |
| default: |
| ERR(handle, "unsupported protocol %u", proto); |
| goto err; |
| } |
| free(addr_buf); |
| free(mask_buf); |
| addr_buf = NULL; |
| mask_buf = NULL; |
| |
| /* Context */ |
| if (context_from_record(handle, policydb, &tmp_con, |
| sepol_node_get_con(data)) < 0) |
| goto err; |
| context_cpy(&tmp_node->context[0], tmp_con); |
| context_destroy(tmp_con); |
| free(tmp_con); |
| tmp_con = NULL; |
| |
| *node = tmp_node; |
| return STATUS_SUCCESS; |
| |
| omem: |
| ERR(handle, "out of memory"); |
| |
| err: |
| if (tmp_node != NULL) { |
| context_destroy(&tmp_node->context[0]); |
| free(tmp_node); |
| } |
| context_destroy(tmp_con); |
| free(tmp_con); |
| free(addr_buf); |
| free(mask_buf); |
| ERR(handle, "could not create node structure"); |
| return STATUS_ERR; |
| } |
| |
| static int node_to_record(sepol_handle_t * handle, |
| const policydb_t * policydb, |
| ocontext_t * node, int proto, sepol_node_t ** record) |
| { |
| |
| context_struct_t *con = &node->context[0]; |
| |
| sepol_context_t *tmp_con = NULL; |
| sepol_node_t *tmp_record = NULL; |
| |
| if (sepol_node_create(handle, &tmp_record) < 0) |
| goto err; |
| |
| sepol_node_set_proto(tmp_record, proto); |
| |
| switch (proto) { |
| |
| case SEPOL_PROTO_IP4: |
| if (sepol_node_set_addr_bytes(handle, tmp_record, |
| (const char *)&node->u.node.addr, |
| 4) < 0) |
| goto err; |
| |
| if (sepol_node_set_mask_bytes(handle, tmp_record, |
| (const char *)&node->u.node.mask, |
| 4) < 0) |
| goto err; |
| break; |
| |
| case SEPOL_PROTO_IP6: |
| if (sepol_node_set_addr_bytes(handle, tmp_record, |
| (const char *)&node->u.node6.addr, |
| 16) < 0) |
| goto err; |
| |
| if (sepol_node_set_mask_bytes(handle, tmp_record, |
| (const char *)&node->u.node6.mask, |
| 16) < 0) |
| goto err; |
| break; |
| |
| default: |
| ERR(handle, "unsupported protocol %u", proto); |
| goto err; |
| } |
| |
| if (context_to_record(handle, policydb, con, &tmp_con) < 0) |
| goto err; |
| |
| if (sepol_node_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 node to record"); |
| sepol_context_free(tmp_con); |
| sepol_node_free(tmp_record); |
| return STATUS_ERR; |
| } |
| |
| /* Return the number of nodes */ |
| extern int sepol_node_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_NODE]; |
| for (c = head; c != NULL; c = c->next) |
| count++; |
| |
| head = policydb->ocontexts[OCON_NODE6]; |
| for (c = head; c != NULL; c = c->next) |
| count++; |
| |
| *response = count; |
| |
| return STATUS_SUCCESS; |
| } |
| |
| /* Check if a node exists */ |
| int sepol_node_exists(sepol_handle_t * handle, |
| const sepol_policydb_t * p, |
| const sepol_node_key_t * key, int *response) |
| { |
| |
| const policydb_t *policydb = &p->p; |
| ocontext_t *c, *head; |
| |
| int proto; |
| const char *addr, *mask; |
| sepol_node_key_unpack(key, &addr, &mask, &proto); |
| |
| switch (proto) { |
| |
| case SEPOL_PROTO_IP4: |
| { |
| head = policydb->ocontexts[OCON_NODE]; |
| for (c = head; c; c = c->next) { |
| unsigned int *addr2 = &c->u.node.addr; |
| unsigned int *mask2 = &c->u.node.mask; |
| |
| if (!memcmp(addr, addr2, 4) && |
| !memcmp(mask, mask2, 4)) { |
| |
| *response = 1; |
| return STATUS_SUCCESS; |
| } |
| } |
| break; |
| } |
| case SEPOL_PROTO_IP6: |
| { |
| head = policydb->ocontexts[OCON_NODE6]; |
| for (c = head; c; c = c->next) { |
| unsigned int *addr2 = c->u.node6.addr; |
| unsigned int *mask2 = c->u.node6.mask; |
| |
| if (!memcmp(addr, addr2, 16) && |
| !memcmp(mask, mask2, 16)) { |
| *response = 1; |
| return STATUS_SUCCESS; |
| } |
| } |
| break; |
| } |
| default: |
| ERR(handle, "unsupported protocol %u", proto); |
| goto err; |
| } |
| |
| *response = 0; |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not check if node %s/%s (%s) exists", |
| addr, mask, sepol_node_get_proto_str(proto)); |
| return STATUS_ERR; |
| } |
| |
| /* Query a node */ |
| int sepol_node_query(sepol_handle_t * handle, |
| const sepol_policydb_t * p, |
| const sepol_node_key_t * key, sepol_node_t ** response) |
| { |
| |
| const policydb_t *policydb = &p->p; |
| ocontext_t *c, *head; |
| |
| int proto; |
| const char *addr, *mask; |
| sepol_node_key_unpack(key, &addr, &mask, &proto); |
| |
| switch (proto) { |
| |
| case SEPOL_PROTO_IP4: |
| { |
| head = policydb->ocontexts[OCON_NODE]; |
| for (c = head; c; c = c->next) { |
| unsigned int *addr2 = &c->u.node.addr; |
| unsigned int *mask2 = &c->u.node.mask; |
| |
| if (!memcmp(addr, addr2, 4) && |
| !memcmp(mask, mask2, 4)) { |
| |
| if (node_to_record(handle, policydb, |
| c, SEPOL_PROTO_IP4, |
| response) < 0) |
| goto err; |
| return STATUS_SUCCESS; |
| } |
| } |
| break; |
| } |
| case SEPOL_PROTO_IP6: |
| { |
| head = policydb->ocontexts[OCON_NODE6]; |
| for (c = head; c; c = c->next) { |
| unsigned int *addr2 = c->u.node6.addr; |
| unsigned int *mask2 = c->u.node6.mask; |
| |
| if (!memcmp(addr, addr2, 16) && |
| !memcmp(mask, mask2, 16)) { |
| |
| if (node_to_record(handle, policydb, |
| c, SEPOL_PROTO_IP6, |
| response) < 0) |
| goto err; |
| return STATUS_SUCCESS; |
| } |
| } |
| break; |
| } |
| default: |
| ERR(handle, "unsupported protocol %u", proto); |
| goto err; |
| } |
| *response = NULL; |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not query node %s/%s (%s)", |
| addr, mask, sepol_node_get_proto_str(proto)); |
| return STATUS_ERR; |
| |
| } |
| |
| /* Load a node into policy */ |
| int sepol_node_modify(sepol_handle_t * handle, |
| sepol_policydb_t * p, |
| const sepol_node_key_t * key, const sepol_node_t * data) |
| { |
| |
| policydb_t *policydb = &p->p; |
| ocontext_t *node = NULL; |
| |
| int proto; |
| const char *addr, *mask; |
| |
| sepol_node_key_unpack(key, &addr, &mask, &proto); |
| |
| if (node_from_record(handle, policydb, &node, data) < 0) |
| goto err; |
| |
| switch (proto) { |
| |
| case SEPOL_PROTO_IP4: |
| { |
| /* Attach to context list */ |
| node->next = policydb->ocontexts[OCON_NODE]; |
| policydb->ocontexts[OCON_NODE] = node; |
| break; |
| } |
| case SEPOL_PROTO_IP6: |
| { |
| /* Attach to context list */ |
| node->next = policydb->ocontexts[OCON_NODE6]; |
| policydb->ocontexts[OCON_NODE6] = node; |
| break; |
| } |
| default: |
| ERR(handle, "unsupported protocol %u", proto); |
| goto err; |
| } |
| |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not load node %s/%s (%s)", |
| addr, mask, sepol_node_get_proto_str(proto)); |
| if (node != NULL) { |
| context_destroy(&node->context[0]); |
| free(node); |
| } |
| return STATUS_ERR; |
| } |
| |
| int sepol_node_iterate(sepol_handle_t * handle, |
| const sepol_policydb_t * p, |
| int (*fn) (const sepol_node_t * node, |
| void *fn_arg), void *arg) |
| { |
| |
| const policydb_t *policydb = &p->p; |
| ocontext_t *c, *head; |
| sepol_node_t *node = NULL; |
| int status; |
| |
| head = policydb->ocontexts[OCON_NODE]; |
| for (c = head; c; c = c->next) { |
| if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP4, &node) |
| < 0) |
| goto err; |
| |
| /* Invoke handler */ |
| status = fn(node, arg); |
| if (status < 0) |
| goto err; |
| |
| sepol_node_free(node); |
| node = NULL; |
| |
| /* Handler requested exit */ |
| if (status > 0) |
| break; |
| } |
| |
| head = policydb->ocontexts[OCON_NODE6]; |
| for (c = head; c; c = c->next) { |
| if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP6, &node) |
| < 0) |
| goto err; |
| |
| /* Invoke handler */ |
| status = fn(node, arg); |
| if (status < 0) |
| goto err; |
| |
| sepol_node_free(node); |
| node = NULL; |
| |
| /* Handler requested exit */ |
| if (status > 0) |
| break; |
| } |
| |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not iterate over nodes"); |
| sepol_node_free(node); |
| return STATUS_ERR; |
| } |