16cd6a6acSopenharmony_ci#include <netinet/in.h>
26cd6a6acSopenharmony_ci#include <arpa/inet.h>
36cd6a6acSopenharmony_ci#include <stdlib.h>
46cd6a6acSopenharmony_ci
56cd6a6acSopenharmony_ci#include "debug.h"
66cd6a6acSopenharmony_ci#include "context.h"
76cd6a6acSopenharmony_ci#include "handle.h"
86cd6a6acSopenharmony_ci
96cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h>
106cd6a6acSopenharmony_ci#include "node_internal.h"
116cd6a6acSopenharmony_ci
126cd6a6acSopenharmony_ci/* Create a low level node structure from
136cd6a6acSopenharmony_ci * a high level representation */
146cd6a6acSopenharmony_cistatic int node_from_record(sepol_handle_t * handle,
156cd6a6acSopenharmony_ci			    const policydb_t * policydb,
166cd6a6acSopenharmony_ci			    ocontext_t ** node, const sepol_node_t * data)
176cd6a6acSopenharmony_ci{
186cd6a6acSopenharmony_ci
196cd6a6acSopenharmony_ci	ocontext_t *tmp_node = NULL;
206cd6a6acSopenharmony_ci	context_struct_t *tmp_con = NULL;
216cd6a6acSopenharmony_ci	char *addr_buf = NULL, *mask_buf = NULL;
226cd6a6acSopenharmony_ci	size_t addr_bsize, mask_bsize;
236cd6a6acSopenharmony_ci	int proto;
246cd6a6acSopenharmony_ci
256cd6a6acSopenharmony_ci	tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t));
266cd6a6acSopenharmony_ci	if (!tmp_node)
276cd6a6acSopenharmony_ci		goto omem;
286cd6a6acSopenharmony_ci
296cd6a6acSopenharmony_ci	/* Address and netmask */
306cd6a6acSopenharmony_ci	if (sepol_node_get_addr_bytes(handle, data, &addr_buf, &addr_bsize) < 0)
316cd6a6acSopenharmony_ci		goto err;
326cd6a6acSopenharmony_ci	if (sepol_node_get_mask_bytes(handle, data, &mask_buf, &mask_bsize) < 0)
336cd6a6acSopenharmony_ci		goto err;
346cd6a6acSopenharmony_ci
356cd6a6acSopenharmony_ci	proto = sepol_node_get_proto(data);
366cd6a6acSopenharmony_ci
376cd6a6acSopenharmony_ci	switch (proto) {
386cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP4:
396cd6a6acSopenharmony_ci		memcpy(&tmp_node->u.node.addr, addr_buf, addr_bsize);
406cd6a6acSopenharmony_ci		memcpy(&tmp_node->u.node.mask, mask_buf, mask_bsize);
416cd6a6acSopenharmony_ci		break;
426cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP6:
436cd6a6acSopenharmony_ci		memcpy(tmp_node->u.node6.addr, addr_buf, addr_bsize);
446cd6a6acSopenharmony_ci		memcpy(tmp_node->u.node6.mask, mask_buf, mask_bsize);
456cd6a6acSopenharmony_ci		break;
466cd6a6acSopenharmony_ci	default:
476cd6a6acSopenharmony_ci		ERR(handle, "unsupported protocol %u", proto);
486cd6a6acSopenharmony_ci		goto err;
496cd6a6acSopenharmony_ci	}
506cd6a6acSopenharmony_ci	free(addr_buf);
516cd6a6acSopenharmony_ci	free(mask_buf);
526cd6a6acSopenharmony_ci	addr_buf = NULL;
536cd6a6acSopenharmony_ci	mask_buf = NULL;
546cd6a6acSopenharmony_ci
556cd6a6acSopenharmony_ci	/* Context */
566cd6a6acSopenharmony_ci	if (context_from_record(handle, policydb, &tmp_con,
576cd6a6acSopenharmony_ci				sepol_node_get_con(data)) < 0)
586cd6a6acSopenharmony_ci		goto err;
596cd6a6acSopenharmony_ci	context_cpy(&tmp_node->context[0], tmp_con);
606cd6a6acSopenharmony_ci	context_destroy(tmp_con);
616cd6a6acSopenharmony_ci	free(tmp_con);
626cd6a6acSopenharmony_ci	tmp_con = NULL;
636cd6a6acSopenharmony_ci
646cd6a6acSopenharmony_ci	*node = tmp_node;
656cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
666cd6a6acSopenharmony_ci
676cd6a6acSopenharmony_ci      omem:
686cd6a6acSopenharmony_ci	ERR(handle, "out of memory");
696cd6a6acSopenharmony_ci
706cd6a6acSopenharmony_ci      err:
716cd6a6acSopenharmony_ci	if (tmp_node != NULL) {
726cd6a6acSopenharmony_ci		context_destroy(&tmp_node->context[0]);
736cd6a6acSopenharmony_ci		free(tmp_node);
746cd6a6acSopenharmony_ci	}
756cd6a6acSopenharmony_ci	context_destroy(tmp_con);
766cd6a6acSopenharmony_ci	free(tmp_con);
776cd6a6acSopenharmony_ci	free(addr_buf);
786cd6a6acSopenharmony_ci	free(mask_buf);
796cd6a6acSopenharmony_ci	ERR(handle, "could not create node structure");
806cd6a6acSopenharmony_ci	return STATUS_ERR;
816cd6a6acSopenharmony_ci}
826cd6a6acSopenharmony_ci
836cd6a6acSopenharmony_cistatic int node_to_record(sepol_handle_t * handle,
846cd6a6acSopenharmony_ci			  const policydb_t * policydb,
856cd6a6acSopenharmony_ci			  ocontext_t * node, int proto, sepol_node_t ** record)
866cd6a6acSopenharmony_ci{
876cd6a6acSopenharmony_ci
886cd6a6acSopenharmony_ci	context_struct_t *con = &node->context[0];
896cd6a6acSopenharmony_ci
906cd6a6acSopenharmony_ci	sepol_context_t *tmp_con = NULL;
916cd6a6acSopenharmony_ci	sepol_node_t *tmp_record = NULL;
926cd6a6acSopenharmony_ci
936cd6a6acSopenharmony_ci	if (sepol_node_create(handle, &tmp_record) < 0)
946cd6a6acSopenharmony_ci		goto err;
956cd6a6acSopenharmony_ci
966cd6a6acSopenharmony_ci	sepol_node_set_proto(tmp_record, proto);
976cd6a6acSopenharmony_ci
986cd6a6acSopenharmony_ci	switch (proto) {
996cd6a6acSopenharmony_ci
1006cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP4:
1016cd6a6acSopenharmony_ci		if (sepol_node_set_addr_bytes(handle, tmp_record,
1026cd6a6acSopenharmony_ci					      (const char *)&node->u.node.addr,
1036cd6a6acSopenharmony_ci					      4) < 0)
1046cd6a6acSopenharmony_ci			goto err;
1056cd6a6acSopenharmony_ci
1066cd6a6acSopenharmony_ci		if (sepol_node_set_mask_bytes(handle, tmp_record,
1076cd6a6acSopenharmony_ci					      (const char *)&node->u.node.mask,
1086cd6a6acSopenharmony_ci					      4) < 0)
1096cd6a6acSopenharmony_ci			goto err;
1106cd6a6acSopenharmony_ci		break;
1116cd6a6acSopenharmony_ci
1126cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP6:
1136cd6a6acSopenharmony_ci		if (sepol_node_set_addr_bytes(handle, tmp_record,
1146cd6a6acSopenharmony_ci					      (const char *)&node->u.node6.addr,
1156cd6a6acSopenharmony_ci					      16) < 0)
1166cd6a6acSopenharmony_ci			goto err;
1176cd6a6acSopenharmony_ci
1186cd6a6acSopenharmony_ci		if (sepol_node_set_mask_bytes(handle, tmp_record,
1196cd6a6acSopenharmony_ci					      (const char *)&node->u.node6.mask,
1206cd6a6acSopenharmony_ci					      16) < 0)
1216cd6a6acSopenharmony_ci			goto err;
1226cd6a6acSopenharmony_ci		break;
1236cd6a6acSopenharmony_ci
1246cd6a6acSopenharmony_ci	default:
1256cd6a6acSopenharmony_ci		ERR(handle, "unsupported protocol %u", proto);
1266cd6a6acSopenharmony_ci		goto err;
1276cd6a6acSopenharmony_ci	}
1286cd6a6acSopenharmony_ci
1296cd6a6acSopenharmony_ci	if (context_to_record(handle, policydb, con, &tmp_con) < 0)
1306cd6a6acSopenharmony_ci		goto err;
1316cd6a6acSopenharmony_ci
1326cd6a6acSopenharmony_ci	if (sepol_node_set_con(handle, tmp_record, tmp_con) < 0)
1336cd6a6acSopenharmony_ci		goto err;
1346cd6a6acSopenharmony_ci
1356cd6a6acSopenharmony_ci	sepol_context_free(tmp_con);
1366cd6a6acSopenharmony_ci	*record = tmp_record;
1376cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1386cd6a6acSopenharmony_ci
1396cd6a6acSopenharmony_ci      err:
1406cd6a6acSopenharmony_ci	ERR(handle, "could not convert node to record");
1416cd6a6acSopenharmony_ci	sepol_context_free(tmp_con);
1426cd6a6acSopenharmony_ci	sepol_node_free(tmp_record);
1436cd6a6acSopenharmony_ci	return STATUS_ERR;
1446cd6a6acSopenharmony_ci}
1456cd6a6acSopenharmony_ci
1466cd6a6acSopenharmony_ci/* Return the number of nodes */
1476cd6a6acSopenharmony_ciextern int sepol_node_count(sepol_handle_t * handle __attribute__ ((unused)),
1486cd6a6acSopenharmony_ci			    const sepol_policydb_t * p, unsigned int *response)
1496cd6a6acSopenharmony_ci{
1506cd6a6acSopenharmony_ci
1516cd6a6acSopenharmony_ci	unsigned int count = 0;
1526cd6a6acSopenharmony_ci	ocontext_t *c, *head;
1536cd6a6acSopenharmony_ci	const policydb_t *policydb = &p->p;
1546cd6a6acSopenharmony_ci
1556cd6a6acSopenharmony_ci	head = policydb->ocontexts[OCON_NODE];
1566cd6a6acSopenharmony_ci	for (c = head; c != NULL; c = c->next)
1576cd6a6acSopenharmony_ci		count++;
1586cd6a6acSopenharmony_ci
1596cd6a6acSopenharmony_ci	head = policydb->ocontexts[OCON_NODE6];
1606cd6a6acSopenharmony_ci	for (c = head; c != NULL; c = c->next)
1616cd6a6acSopenharmony_ci		count++;
1626cd6a6acSopenharmony_ci
1636cd6a6acSopenharmony_ci	*response = count;
1646cd6a6acSopenharmony_ci
1656cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1666cd6a6acSopenharmony_ci}
1676cd6a6acSopenharmony_ci
1686cd6a6acSopenharmony_ci/* Check if a node exists */
1696cd6a6acSopenharmony_ciint sepol_node_exists(sepol_handle_t * handle,
1706cd6a6acSopenharmony_ci		      const sepol_policydb_t * p,
1716cd6a6acSopenharmony_ci		      const sepol_node_key_t * key, int *response)
1726cd6a6acSopenharmony_ci{
1736cd6a6acSopenharmony_ci
1746cd6a6acSopenharmony_ci	const policydb_t *policydb = &p->p;
1756cd6a6acSopenharmony_ci	ocontext_t *c, *head;
1766cd6a6acSopenharmony_ci
1776cd6a6acSopenharmony_ci	int proto;
1786cd6a6acSopenharmony_ci	const char *addr, *mask;
1796cd6a6acSopenharmony_ci	sepol_node_key_unpack(key, &addr, &mask, &proto);
1806cd6a6acSopenharmony_ci
1816cd6a6acSopenharmony_ci	switch (proto) {
1826cd6a6acSopenharmony_ci
1836cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP4:
1846cd6a6acSopenharmony_ci		{
1856cd6a6acSopenharmony_ci			head = policydb->ocontexts[OCON_NODE];
1866cd6a6acSopenharmony_ci			for (c = head; c; c = c->next) {
1876cd6a6acSopenharmony_ci				unsigned int *addr2 = &c->u.node.addr;
1886cd6a6acSopenharmony_ci				unsigned int *mask2 = &c->u.node.mask;
1896cd6a6acSopenharmony_ci
1906cd6a6acSopenharmony_ci				if (!memcmp(addr, addr2, 4) &&
1916cd6a6acSopenharmony_ci				    !memcmp(mask, mask2, 4)) {
1926cd6a6acSopenharmony_ci
1936cd6a6acSopenharmony_ci					*response = 1;
1946cd6a6acSopenharmony_ci					return STATUS_SUCCESS;
1956cd6a6acSopenharmony_ci				}
1966cd6a6acSopenharmony_ci			}
1976cd6a6acSopenharmony_ci			break;
1986cd6a6acSopenharmony_ci		}
1996cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP6:
2006cd6a6acSopenharmony_ci		{
2016cd6a6acSopenharmony_ci			head = policydb->ocontexts[OCON_NODE6];
2026cd6a6acSopenharmony_ci			for (c = head; c; c = c->next) {
2036cd6a6acSopenharmony_ci				unsigned int *addr2 = c->u.node6.addr;
2046cd6a6acSopenharmony_ci				unsigned int *mask2 = c->u.node6.mask;
2056cd6a6acSopenharmony_ci
2066cd6a6acSopenharmony_ci				if (!memcmp(addr, addr2, 16) &&
2076cd6a6acSopenharmony_ci				    !memcmp(mask, mask2, 16)) {
2086cd6a6acSopenharmony_ci					*response = 1;
2096cd6a6acSopenharmony_ci					return STATUS_SUCCESS;
2106cd6a6acSopenharmony_ci				}
2116cd6a6acSopenharmony_ci			}
2126cd6a6acSopenharmony_ci			break;
2136cd6a6acSopenharmony_ci		}
2146cd6a6acSopenharmony_ci	default:
2156cd6a6acSopenharmony_ci		ERR(handle, "unsupported protocol %u", proto);
2166cd6a6acSopenharmony_ci		goto err;
2176cd6a6acSopenharmony_ci	}
2186cd6a6acSopenharmony_ci
2196cd6a6acSopenharmony_ci	*response = 0;
2206cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
2216cd6a6acSopenharmony_ci
2226cd6a6acSopenharmony_ci      err:
2236cd6a6acSopenharmony_ci	ERR(handle, "could not check if node %s/%s (%s) exists",
2246cd6a6acSopenharmony_ci	    addr, mask, sepol_node_get_proto_str(proto));
2256cd6a6acSopenharmony_ci	return STATUS_ERR;
2266cd6a6acSopenharmony_ci}
2276cd6a6acSopenharmony_ci
2286cd6a6acSopenharmony_ci/* Query a node */
2296cd6a6acSopenharmony_ciint sepol_node_query(sepol_handle_t * handle,
2306cd6a6acSopenharmony_ci		     const sepol_policydb_t * p,
2316cd6a6acSopenharmony_ci		     const sepol_node_key_t * key, sepol_node_t ** response)
2326cd6a6acSopenharmony_ci{
2336cd6a6acSopenharmony_ci
2346cd6a6acSopenharmony_ci	const policydb_t *policydb = &p->p;
2356cd6a6acSopenharmony_ci	ocontext_t *c, *head;
2366cd6a6acSopenharmony_ci
2376cd6a6acSopenharmony_ci	int proto;
2386cd6a6acSopenharmony_ci	const char *addr, *mask;
2396cd6a6acSopenharmony_ci	sepol_node_key_unpack(key, &addr, &mask, &proto);
2406cd6a6acSopenharmony_ci
2416cd6a6acSopenharmony_ci	switch (proto) {
2426cd6a6acSopenharmony_ci
2436cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP4:
2446cd6a6acSopenharmony_ci		{
2456cd6a6acSopenharmony_ci			head = policydb->ocontexts[OCON_NODE];
2466cd6a6acSopenharmony_ci			for (c = head; c; c = c->next) {
2476cd6a6acSopenharmony_ci				unsigned int *addr2 = &c->u.node.addr;
2486cd6a6acSopenharmony_ci				unsigned int *mask2 = &c->u.node.mask;
2496cd6a6acSopenharmony_ci
2506cd6a6acSopenharmony_ci				if (!memcmp(addr, addr2, 4) &&
2516cd6a6acSopenharmony_ci				    !memcmp(mask, mask2, 4)) {
2526cd6a6acSopenharmony_ci
2536cd6a6acSopenharmony_ci					if (node_to_record(handle, policydb,
2546cd6a6acSopenharmony_ci							   c, SEPOL_PROTO_IP4,
2556cd6a6acSopenharmony_ci							   response) < 0)
2566cd6a6acSopenharmony_ci						goto err;
2576cd6a6acSopenharmony_ci					return STATUS_SUCCESS;
2586cd6a6acSopenharmony_ci				}
2596cd6a6acSopenharmony_ci			}
2606cd6a6acSopenharmony_ci			break;
2616cd6a6acSopenharmony_ci		}
2626cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP6:
2636cd6a6acSopenharmony_ci		{
2646cd6a6acSopenharmony_ci			head = policydb->ocontexts[OCON_NODE6];
2656cd6a6acSopenharmony_ci			for (c = head; c; c = c->next) {
2666cd6a6acSopenharmony_ci				unsigned int *addr2 = c->u.node6.addr;
2676cd6a6acSopenharmony_ci				unsigned int *mask2 = c->u.node6.mask;
2686cd6a6acSopenharmony_ci
2696cd6a6acSopenharmony_ci				if (!memcmp(addr, addr2, 16) &&
2706cd6a6acSopenharmony_ci				    !memcmp(mask, mask2, 16)) {
2716cd6a6acSopenharmony_ci
2726cd6a6acSopenharmony_ci					if (node_to_record(handle, policydb,
2736cd6a6acSopenharmony_ci							   c, SEPOL_PROTO_IP6,
2746cd6a6acSopenharmony_ci							   response) < 0)
2756cd6a6acSopenharmony_ci						goto err;
2766cd6a6acSopenharmony_ci					return STATUS_SUCCESS;
2776cd6a6acSopenharmony_ci				}
2786cd6a6acSopenharmony_ci			}
2796cd6a6acSopenharmony_ci			break;
2806cd6a6acSopenharmony_ci		}
2816cd6a6acSopenharmony_ci	default:
2826cd6a6acSopenharmony_ci		ERR(handle, "unsupported protocol %u", proto);
2836cd6a6acSopenharmony_ci		goto err;
2846cd6a6acSopenharmony_ci	}
2856cd6a6acSopenharmony_ci	*response = NULL;
2866cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
2876cd6a6acSopenharmony_ci
2886cd6a6acSopenharmony_ci      err:
2896cd6a6acSopenharmony_ci	ERR(handle, "could not query node %s/%s (%s)",
2906cd6a6acSopenharmony_ci	    addr, mask, sepol_node_get_proto_str(proto));
2916cd6a6acSopenharmony_ci	return STATUS_ERR;
2926cd6a6acSopenharmony_ci
2936cd6a6acSopenharmony_ci}
2946cd6a6acSopenharmony_ci
2956cd6a6acSopenharmony_ci/* Load a node into policy */
2966cd6a6acSopenharmony_ciint sepol_node_modify(sepol_handle_t * handle,
2976cd6a6acSopenharmony_ci		      sepol_policydb_t * p,
2986cd6a6acSopenharmony_ci		      const sepol_node_key_t * key, const sepol_node_t * data)
2996cd6a6acSopenharmony_ci{
3006cd6a6acSopenharmony_ci
3016cd6a6acSopenharmony_ci	policydb_t *policydb = &p->p;
3026cd6a6acSopenharmony_ci	ocontext_t *node = NULL;
3036cd6a6acSopenharmony_ci
3046cd6a6acSopenharmony_ci	int proto;
3056cd6a6acSopenharmony_ci	const char *addr, *mask;
3066cd6a6acSopenharmony_ci
3076cd6a6acSopenharmony_ci	sepol_node_key_unpack(key, &addr, &mask, &proto);
3086cd6a6acSopenharmony_ci
3096cd6a6acSopenharmony_ci	if (node_from_record(handle, policydb, &node, data) < 0)
3106cd6a6acSopenharmony_ci		goto err;
3116cd6a6acSopenharmony_ci
3126cd6a6acSopenharmony_ci	switch (proto) {
3136cd6a6acSopenharmony_ci
3146cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP4:
3156cd6a6acSopenharmony_ci		{
3166cd6a6acSopenharmony_ci			/* Attach to context list */
3176cd6a6acSopenharmony_ci			node->next = policydb->ocontexts[OCON_NODE];
3186cd6a6acSopenharmony_ci			policydb->ocontexts[OCON_NODE] = node;
3196cd6a6acSopenharmony_ci			break;
3206cd6a6acSopenharmony_ci		}
3216cd6a6acSopenharmony_ci	case SEPOL_PROTO_IP6:
3226cd6a6acSopenharmony_ci		{
3236cd6a6acSopenharmony_ci			/* Attach to context list */
3246cd6a6acSopenharmony_ci			node->next = policydb->ocontexts[OCON_NODE6];
3256cd6a6acSopenharmony_ci			policydb->ocontexts[OCON_NODE6] = node;
3266cd6a6acSopenharmony_ci			break;
3276cd6a6acSopenharmony_ci		}
3286cd6a6acSopenharmony_ci	default:
3296cd6a6acSopenharmony_ci		ERR(handle, "unsupported protocol %u", proto);
3306cd6a6acSopenharmony_ci		goto err;
3316cd6a6acSopenharmony_ci	}
3326cd6a6acSopenharmony_ci
3336cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
3346cd6a6acSopenharmony_ci
3356cd6a6acSopenharmony_ci      err:
3366cd6a6acSopenharmony_ci	ERR(handle, "could not load node %s/%s (%s)",
3376cd6a6acSopenharmony_ci	    addr, mask, sepol_node_get_proto_str(proto));
3386cd6a6acSopenharmony_ci	if (node != NULL) {
3396cd6a6acSopenharmony_ci		context_destroy(&node->context[0]);
3406cd6a6acSopenharmony_ci		free(node);
3416cd6a6acSopenharmony_ci	}
3426cd6a6acSopenharmony_ci	return STATUS_ERR;
3436cd6a6acSopenharmony_ci}
3446cd6a6acSopenharmony_ci
3456cd6a6acSopenharmony_ciint sepol_node_iterate(sepol_handle_t * handle,
3466cd6a6acSopenharmony_ci		       const sepol_policydb_t * p,
3476cd6a6acSopenharmony_ci		       int (*fn) (const sepol_node_t * node,
3486cd6a6acSopenharmony_ci				  void *fn_arg), void *arg)
3496cd6a6acSopenharmony_ci{
3506cd6a6acSopenharmony_ci
3516cd6a6acSopenharmony_ci	const policydb_t *policydb = &p->p;
3526cd6a6acSopenharmony_ci	ocontext_t *c, *head;
3536cd6a6acSopenharmony_ci	sepol_node_t *node = NULL;
3546cd6a6acSopenharmony_ci	int status;
3556cd6a6acSopenharmony_ci
3566cd6a6acSopenharmony_ci	head = policydb->ocontexts[OCON_NODE];
3576cd6a6acSopenharmony_ci	for (c = head; c; c = c->next) {
3586cd6a6acSopenharmony_ci		if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP4, &node)
3596cd6a6acSopenharmony_ci		    < 0)
3606cd6a6acSopenharmony_ci			goto err;
3616cd6a6acSopenharmony_ci
3626cd6a6acSopenharmony_ci		/* Invoke handler */
3636cd6a6acSopenharmony_ci		status = fn(node, arg);
3646cd6a6acSopenharmony_ci		if (status < 0)
3656cd6a6acSopenharmony_ci			goto err;
3666cd6a6acSopenharmony_ci
3676cd6a6acSopenharmony_ci		sepol_node_free(node);
3686cd6a6acSopenharmony_ci		node = NULL;
3696cd6a6acSopenharmony_ci
3706cd6a6acSopenharmony_ci		/* Handler requested exit */
3716cd6a6acSopenharmony_ci		if (status > 0)
3726cd6a6acSopenharmony_ci			break;
3736cd6a6acSopenharmony_ci	}
3746cd6a6acSopenharmony_ci
3756cd6a6acSopenharmony_ci	head = policydb->ocontexts[OCON_NODE6];
3766cd6a6acSopenharmony_ci	for (c = head; c; c = c->next) {
3776cd6a6acSopenharmony_ci		if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP6, &node)
3786cd6a6acSopenharmony_ci		    < 0)
3796cd6a6acSopenharmony_ci			goto err;
3806cd6a6acSopenharmony_ci
3816cd6a6acSopenharmony_ci		/* Invoke handler */
3826cd6a6acSopenharmony_ci		status = fn(node, arg);
3836cd6a6acSopenharmony_ci		if (status < 0)
3846cd6a6acSopenharmony_ci			goto err;
3856cd6a6acSopenharmony_ci
3866cd6a6acSopenharmony_ci		sepol_node_free(node);
3876cd6a6acSopenharmony_ci		node = NULL;
3886cd6a6acSopenharmony_ci
3896cd6a6acSopenharmony_ci		/* Handler requested exit */
3906cd6a6acSopenharmony_ci		if (status > 0)
3916cd6a6acSopenharmony_ci			break;
3926cd6a6acSopenharmony_ci	}
3936cd6a6acSopenharmony_ci
3946cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
3956cd6a6acSopenharmony_ci
3966cd6a6acSopenharmony_ci      err:
3976cd6a6acSopenharmony_ci	ERR(handle, "could not iterate over nodes");
3986cd6a6acSopenharmony_ci	sepol_node_free(node);
3996cd6a6acSopenharmony_ci	return STATUS_ERR;
4006cd6a6acSopenharmony_ci}
401