#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; tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t)); if (!tmp_node) goto omem; size_t addr_bsize, mask_bsize; /* 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; int 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; handle = NULL; 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; } } 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; }