16cd6a6acSopenharmony_ci/*
26cd6a6acSopenharmony_ci * Generalized labeling frontend for userspace object managers.
36cd6a6acSopenharmony_ci *
46cd6a6acSopenharmony_ci * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
56cd6a6acSopenharmony_ci */
66cd6a6acSopenharmony_ci
76cd6a6acSopenharmony_ci#include <sys/types.h>
86cd6a6acSopenharmony_ci#include <ctype.h>
96cd6a6acSopenharmony_ci#include <errno.h>
106cd6a6acSopenharmony_ci#include <stdio.h>
116cd6a6acSopenharmony_ci#include <stdlib.h>
126cd6a6acSopenharmony_ci#include <string.h>
136cd6a6acSopenharmony_ci#include <sys/stat.h>
146cd6a6acSopenharmony_ci#include <selinux/selinux.h>
156cd6a6acSopenharmony_ci#include "callbacks.h"
166cd6a6acSopenharmony_ci#include "label_internal.h"
176cd6a6acSopenharmony_ci
186cd6a6acSopenharmony_ci#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
196cd6a6acSopenharmony_ci
206cd6a6acSopenharmony_ci#ifdef NO_MEDIA_BACKEND
216cd6a6acSopenharmony_ci#define CONFIG_MEDIA_BACKEND(fnptr) NULL
226cd6a6acSopenharmony_ci#else
236cd6a6acSopenharmony_ci#define CONFIG_MEDIA_BACKEND(fnptr) &fnptr
246cd6a6acSopenharmony_ci#endif
256cd6a6acSopenharmony_ci
266cd6a6acSopenharmony_ci#ifdef NO_X_BACKEND
276cd6a6acSopenharmony_ci#define CONFIG_X_BACKEND(fnptr) NULL
286cd6a6acSopenharmony_ci#else
296cd6a6acSopenharmony_ci#define CONFIG_X_BACKEND(fnptr) &fnptr
306cd6a6acSopenharmony_ci#endif
316cd6a6acSopenharmony_ci
326cd6a6acSopenharmony_ci#ifdef NO_DB_BACKEND
336cd6a6acSopenharmony_ci#define CONFIG_DB_BACKEND(fnptr) NULL
346cd6a6acSopenharmony_ci#else
356cd6a6acSopenharmony_ci#define CONFIG_DB_BACKEND(fnptr) &fnptr
366cd6a6acSopenharmony_ci#endif
376cd6a6acSopenharmony_ci
386cd6a6acSopenharmony_ci#ifdef NO_ANDROID_BACKEND
396cd6a6acSopenharmony_ci#define CONFIG_ANDROID_BACKEND(fnptr) NULL
406cd6a6acSopenharmony_ci#else
416cd6a6acSopenharmony_ci#define CONFIG_ANDROID_BACKEND(fnptr) (&(fnptr))
426cd6a6acSopenharmony_ci#endif
436cd6a6acSopenharmony_ci
446cd6a6acSopenharmony_citypedef int (*selabel_initfunc)(struct selabel_handle *rec,
456cd6a6acSopenharmony_ci				const struct selinux_opt *opts,
466cd6a6acSopenharmony_ci				unsigned nopts);
476cd6a6acSopenharmony_ci
486cd6a6acSopenharmony_cistatic selabel_initfunc initfuncs[] = {
496cd6a6acSopenharmony_ci	&selabel_file_init,
506cd6a6acSopenharmony_ci	CONFIG_MEDIA_BACKEND(selabel_media_init),
516cd6a6acSopenharmony_ci	CONFIG_X_BACKEND(selabel_x_init),
526cd6a6acSopenharmony_ci	CONFIG_DB_BACKEND(selabel_db_init),
536cd6a6acSopenharmony_ci	CONFIG_ANDROID_BACKEND(selabel_property_init),
546cd6a6acSopenharmony_ci	CONFIG_ANDROID_BACKEND(selabel_service_init),
556cd6a6acSopenharmony_ci};
566cd6a6acSopenharmony_ci
576cd6a6acSopenharmony_cistatic inline struct selabel_digest *selabel_is_digest_set
586cd6a6acSopenharmony_ci				    (const struct selinux_opt *opts,
596cd6a6acSopenharmony_ci				    unsigned n,
606cd6a6acSopenharmony_ci				    struct selabel_digest *entry)
616cd6a6acSopenharmony_ci{
626cd6a6acSopenharmony_ci	struct selabel_digest *digest = NULL;
636cd6a6acSopenharmony_ci
646cd6a6acSopenharmony_ci	while (n--) {
656cd6a6acSopenharmony_ci		if (opts[n].type == SELABEL_OPT_DIGEST &&
666cd6a6acSopenharmony_ci					    opts[n].value == (char *)1) {
676cd6a6acSopenharmony_ci			digest = calloc(1, sizeof(*digest));
686cd6a6acSopenharmony_ci			if (!digest)
696cd6a6acSopenharmony_ci				goto err;
706cd6a6acSopenharmony_ci
716cd6a6acSopenharmony_ci			digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1);
726cd6a6acSopenharmony_ci			if (!digest->digest)
736cd6a6acSopenharmony_ci				goto err;
746cd6a6acSopenharmony_ci
756cd6a6acSopenharmony_ci			digest->specfile_list = calloc(DIGEST_FILES_MAX,
766cd6a6acSopenharmony_ci							    sizeof(char *));
776cd6a6acSopenharmony_ci			if (!digest->specfile_list)
786cd6a6acSopenharmony_ci				goto err;
796cd6a6acSopenharmony_ci
806cd6a6acSopenharmony_ci			entry = digest;
816cd6a6acSopenharmony_ci			return entry;
826cd6a6acSopenharmony_ci		}
836cd6a6acSopenharmony_ci	}
846cd6a6acSopenharmony_ci	return NULL;
856cd6a6acSopenharmony_ci
866cd6a6acSopenharmony_cierr:
876cd6a6acSopenharmony_ci	if (digest) {
886cd6a6acSopenharmony_ci		free(digest->digest);
896cd6a6acSopenharmony_ci		free(digest->specfile_list);
906cd6a6acSopenharmony_ci		free(digest);
916cd6a6acSopenharmony_ci	}
926cd6a6acSopenharmony_ci	return NULL;
936cd6a6acSopenharmony_ci}
946cd6a6acSopenharmony_ci
956cd6a6acSopenharmony_cistatic void selabel_digest_fini(struct selabel_digest *ptr)
966cd6a6acSopenharmony_ci{
976cd6a6acSopenharmony_ci	int i;
986cd6a6acSopenharmony_ci
996cd6a6acSopenharmony_ci	free(ptr->digest);
1006cd6a6acSopenharmony_ci	free(ptr->hashbuf);
1016cd6a6acSopenharmony_ci
1026cd6a6acSopenharmony_ci	if (ptr->specfile_list) {
1036cd6a6acSopenharmony_ci		for (i = 0; ptr->specfile_list[i]; i++)
1046cd6a6acSopenharmony_ci			free(ptr->specfile_list[i]);
1056cd6a6acSopenharmony_ci		free(ptr->specfile_list);
1066cd6a6acSopenharmony_ci	}
1076cd6a6acSopenharmony_ci	free(ptr);
1086cd6a6acSopenharmony_ci}
1096cd6a6acSopenharmony_ci
1106cd6a6acSopenharmony_ci/*
1116cd6a6acSopenharmony_ci * Validation functions
1126cd6a6acSopenharmony_ci */
1136cd6a6acSopenharmony_ci
1146cd6a6acSopenharmony_cistatic inline int selabel_is_validate_set(const struct selinux_opt *opts,
1156cd6a6acSopenharmony_ci					  unsigned n)
1166cd6a6acSopenharmony_ci{
1176cd6a6acSopenharmony_ci	while (n--)
1186cd6a6acSopenharmony_ci		if (opts[n].type == SELABEL_OPT_VALIDATE)
1196cd6a6acSopenharmony_ci			return !!opts[n].value;
1206cd6a6acSopenharmony_ci
1216cd6a6acSopenharmony_ci	return 0;
1226cd6a6acSopenharmony_ci}
1236cd6a6acSopenharmony_ci
1246cd6a6acSopenharmony_ciint selabel_validate(struct selabel_handle *rec,
1256cd6a6acSopenharmony_ci		     struct selabel_lookup_rec *contexts)
1266cd6a6acSopenharmony_ci{
1276cd6a6acSopenharmony_ci	int rc = 0;
1286cd6a6acSopenharmony_ci
1296cd6a6acSopenharmony_ci	if (!rec->validating || contexts->validated)
1306cd6a6acSopenharmony_ci		goto out;
1316cd6a6acSopenharmony_ci
1326cd6a6acSopenharmony_ci	rc = selinux_validate(&contexts->ctx_raw);
1336cd6a6acSopenharmony_ci	if (rc < 0)
1346cd6a6acSopenharmony_ci		goto out;
1356cd6a6acSopenharmony_ci
1366cd6a6acSopenharmony_ci	contexts->validated = 1;
1376cd6a6acSopenharmony_ciout:
1386cd6a6acSopenharmony_ci	return rc;
1396cd6a6acSopenharmony_ci}
1406cd6a6acSopenharmony_ci
1416cd6a6acSopenharmony_ci/* Public API helpers */
1426cd6a6acSopenharmony_cistatic int selabel_fini(struct selabel_handle *rec,
1436cd6a6acSopenharmony_ci			    struct selabel_lookup_rec *lr,
1446cd6a6acSopenharmony_ci			    int translating)
1456cd6a6acSopenharmony_ci{
1466cd6a6acSopenharmony_ci#ifdef OHOS_FC_INIT
1476cd6a6acSopenharmony_ci	char *path = NULL;
1486cd6a6acSopenharmony_ci	if (rec->spec_file != NULL) {
1496cd6a6acSopenharmony_ci		path = rec->spec_file[0];
1506cd6a6acSopenharmony_ci	}
1516cd6a6acSopenharmony_ci	if (compat_validate(rec, lr, path, lr->lineno))
1526cd6a6acSopenharmony_ci		return -1;
1536cd6a6acSopenharmony_ci#else
1546cd6a6acSopenharmony_ci	if (compat_validate(rec, lr, rec->spec_file, lr->lineno))
1556cd6a6acSopenharmony_ci		return -1;
1566cd6a6acSopenharmony_ci#endif
1576cd6a6acSopenharmony_ci
1586cd6a6acSopenharmony_ci	if (translating && !lr->ctx_trans &&
1596cd6a6acSopenharmony_ci	    selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
1606cd6a6acSopenharmony_ci		return -1;
1616cd6a6acSopenharmony_ci
1626cd6a6acSopenharmony_ci	return 0;
1636cd6a6acSopenharmony_ci}
1646cd6a6acSopenharmony_ci
1656cd6a6acSopenharmony_cistatic struct selabel_lookup_rec *
1666cd6a6acSopenharmony_ciselabel_lookup_common(struct selabel_handle *rec, int translating,
1676cd6a6acSopenharmony_ci		      const char *key, int type)
1686cd6a6acSopenharmony_ci{
1696cd6a6acSopenharmony_ci	struct selabel_lookup_rec *lr;
1706cd6a6acSopenharmony_ci
1716cd6a6acSopenharmony_ci	if (key == NULL) {
1726cd6a6acSopenharmony_ci		errno = EINVAL;
1736cd6a6acSopenharmony_ci		return NULL;
1746cd6a6acSopenharmony_ci	}
1756cd6a6acSopenharmony_ci
1766cd6a6acSopenharmony_ci	lr = rec->func_lookup(rec, key, type);
1776cd6a6acSopenharmony_ci	if (!lr)
1786cd6a6acSopenharmony_ci		return NULL;
1796cd6a6acSopenharmony_ci
1806cd6a6acSopenharmony_ci	if (selabel_fini(rec, lr, translating))
1816cd6a6acSopenharmony_ci		return NULL;
1826cd6a6acSopenharmony_ci
1836cd6a6acSopenharmony_ci	return lr;
1846cd6a6acSopenharmony_ci}
1856cd6a6acSopenharmony_ci
1866cd6a6acSopenharmony_cistatic struct selabel_lookup_rec *
1876cd6a6acSopenharmony_ciselabel_lookup_bm_common(struct selabel_handle *rec, int translating,
1886cd6a6acSopenharmony_ci		      const char *key, int type, const char **aliases)
1896cd6a6acSopenharmony_ci{
1906cd6a6acSopenharmony_ci	struct selabel_lookup_rec *lr;
1916cd6a6acSopenharmony_ci
1926cd6a6acSopenharmony_ci	if (key == NULL) {
1936cd6a6acSopenharmony_ci		errno = EINVAL;
1946cd6a6acSopenharmony_ci		return NULL;
1956cd6a6acSopenharmony_ci	}
1966cd6a6acSopenharmony_ci
1976cd6a6acSopenharmony_ci	lr = rec->func_lookup_best_match(rec, key, aliases, type);
1986cd6a6acSopenharmony_ci	if (!lr)
1996cd6a6acSopenharmony_ci		return NULL;
2006cd6a6acSopenharmony_ci
2016cd6a6acSopenharmony_ci	if (selabel_fini(rec, lr, translating))
2026cd6a6acSopenharmony_ci		return NULL;
2036cd6a6acSopenharmony_ci
2046cd6a6acSopenharmony_ci	return lr;
2056cd6a6acSopenharmony_ci}
2066cd6a6acSopenharmony_ci
2076cd6a6acSopenharmony_ci#ifdef OHOS_FC_INIT
2086cd6a6acSopenharmony_cistatic void free_spec_files(struct selabel_handle *rec)
2096cd6a6acSopenharmony_ci{
2106cd6a6acSopenharmony_ci	if (rec->spec_file != NULL) {
2116cd6a6acSopenharmony_ci		for (int path_index = 0; path_index < rec->spec_file_nums; path_index++) {
2126cd6a6acSopenharmony_ci			if (rec->spec_file[path_index] != NULL) {
2136cd6a6acSopenharmony_ci				free(rec->spec_file[path_index]);
2146cd6a6acSopenharmony_ci			}
2156cd6a6acSopenharmony_ci		}
2166cd6a6acSopenharmony_ci		free(rec->spec_file);
2176cd6a6acSopenharmony_ci	}
2186cd6a6acSopenharmony_ci}
2196cd6a6acSopenharmony_ci#endif
2206cd6a6acSopenharmony_ci
2216cd6a6acSopenharmony_ci/*
2226cd6a6acSopenharmony_ci * Public API
2236cd6a6acSopenharmony_ci */
2246cd6a6acSopenharmony_ci
2256cd6a6acSopenharmony_cistruct selabel_handle *selabel_open(unsigned int backend,
2266cd6a6acSopenharmony_ci				    const struct selinux_opt *opts,
2276cd6a6acSopenharmony_ci				    unsigned nopts)
2286cd6a6acSopenharmony_ci{
2296cd6a6acSopenharmony_ci	struct selabel_handle *rec = NULL;
2306cd6a6acSopenharmony_ci
2316cd6a6acSopenharmony_ci	if (backend >= ARRAY_SIZE(initfuncs)) {
2326cd6a6acSopenharmony_ci		errno = EINVAL;
2336cd6a6acSopenharmony_ci		goto out;
2346cd6a6acSopenharmony_ci	}
2356cd6a6acSopenharmony_ci
2366cd6a6acSopenharmony_ci	if (!initfuncs[backend]) {
2376cd6a6acSopenharmony_ci		errno = ENOTSUP;
2386cd6a6acSopenharmony_ci		goto out;
2396cd6a6acSopenharmony_ci	}
2406cd6a6acSopenharmony_ci
2416cd6a6acSopenharmony_ci	rec = (struct selabel_handle *)malloc(sizeof(*rec));
2426cd6a6acSopenharmony_ci	if (!rec)
2436cd6a6acSopenharmony_ci		goto out;
2446cd6a6acSopenharmony_ci
2456cd6a6acSopenharmony_ci	memset(rec, 0, sizeof(*rec));
2466cd6a6acSopenharmony_ci	rec->backend = backend;
2476cd6a6acSopenharmony_ci	rec->validating = selabel_is_validate_set(opts, nopts);
2486cd6a6acSopenharmony_ci
2496cd6a6acSopenharmony_ci	rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
2506cd6a6acSopenharmony_ci
2516cd6a6acSopenharmony_ci	if ((*initfuncs[backend])(rec, opts, nopts)) {
2526cd6a6acSopenharmony_ci		if (rec->digest)
2536cd6a6acSopenharmony_ci			selabel_digest_fini(rec->digest);
2546cd6a6acSopenharmony_ci#ifdef OHOS_FC_INIT
2556cd6a6acSopenharmony_ci		free_spec_files(rec);
2566cd6a6acSopenharmony_ci#else
2576cd6a6acSopenharmony_ci		free(rec->spec_file);
2586cd6a6acSopenharmony_ci#endif
2596cd6a6acSopenharmony_ci		free(rec);
2606cd6a6acSopenharmony_ci		rec = NULL;
2616cd6a6acSopenharmony_ci	}
2626cd6a6acSopenharmony_ci
2636cd6a6acSopenharmony_ciout:
2646cd6a6acSopenharmony_ci	return rec;
2656cd6a6acSopenharmony_ci}
2666cd6a6acSopenharmony_ci
2676cd6a6acSopenharmony_ciint selabel_lookup(struct selabel_handle *rec, char **con,
2686cd6a6acSopenharmony_ci		   const char *key, int type)
2696cd6a6acSopenharmony_ci{
2706cd6a6acSopenharmony_ci	struct selabel_lookup_rec *lr;
2716cd6a6acSopenharmony_ci
2726cd6a6acSopenharmony_ci	lr = selabel_lookup_common(rec, 1, key, type);
2736cd6a6acSopenharmony_ci	if (!lr)
2746cd6a6acSopenharmony_ci		return -1;
2756cd6a6acSopenharmony_ci
2766cd6a6acSopenharmony_ci	*con = strdup(lr->ctx_trans);
2776cd6a6acSopenharmony_ci	return *con ? 0 : -1;
2786cd6a6acSopenharmony_ci}
2796cd6a6acSopenharmony_ci
2806cd6a6acSopenharmony_ciint selabel_lookup_raw(struct selabel_handle *rec, char **con,
2816cd6a6acSopenharmony_ci		       const char *key, int type)
2826cd6a6acSopenharmony_ci{
2836cd6a6acSopenharmony_ci	struct selabel_lookup_rec *lr;
2846cd6a6acSopenharmony_ci
2856cd6a6acSopenharmony_ci	lr = selabel_lookup_common(rec, 0, key, type);
2866cd6a6acSopenharmony_ci	if (!lr)
2876cd6a6acSopenharmony_ci		return -1;
2886cd6a6acSopenharmony_ci
2896cd6a6acSopenharmony_ci	*con = strdup(lr->ctx_raw);
2906cd6a6acSopenharmony_ci	return *con ? 0 : -1;
2916cd6a6acSopenharmony_ci}
2926cd6a6acSopenharmony_ci
2936cd6a6acSopenharmony_cibool selabel_partial_match(struct selabel_handle *rec, const char *key)
2946cd6a6acSopenharmony_ci{
2956cd6a6acSopenharmony_ci	if (!rec->func_partial_match) {
2966cd6a6acSopenharmony_ci		/*
2976cd6a6acSopenharmony_ci		 * If the label backend does not support partial matching,
2986cd6a6acSopenharmony_ci		 * then assume a match is possible.
2996cd6a6acSopenharmony_ci		 */
3006cd6a6acSopenharmony_ci		return true;
3016cd6a6acSopenharmony_ci	}
3026cd6a6acSopenharmony_ci
3036cd6a6acSopenharmony_ci	return rec->func_partial_match(rec, key);
3046cd6a6acSopenharmony_ci}
3056cd6a6acSopenharmony_ci
3066cd6a6acSopenharmony_cibool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
3076cd6a6acSopenharmony_ci					     const char *key,
3086cd6a6acSopenharmony_ci					     uint8_t **calculated_digest,
3096cd6a6acSopenharmony_ci					     uint8_t **xattr_digest,
3106cd6a6acSopenharmony_ci					     size_t *digest_len)
3116cd6a6acSopenharmony_ci{
3126cd6a6acSopenharmony_ci	if (!rec->func_get_digests_all_partial_matches)
3136cd6a6acSopenharmony_ci		return false;
3146cd6a6acSopenharmony_ci
3156cd6a6acSopenharmony_ci	return rec->func_get_digests_all_partial_matches(rec, key,
3166cd6a6acSopenharmony_ci							 calculated_digest,
3176cd6a6acSopenharmony_ci							 xattr_digest,
3186cd6a6acSopenharmony_ci							 digest_len);
3196cd6a6acSopenharmony_ci}
3206cd6a6acSopenharmony_ci
3216cd6a6acSopenharmony_cibool selabel_hash_all_partial_matches(struct selabel_handle *rec,
3226cd6a6acSopenharmony_ci                                      const char *key, uint8_t *digest) {
3236cd6a6acSopenharmony_ci	if (!rec->func_hash_all_partial_matches) {
3246cd6a6acSopenharmony_ci		return false;
3256cd6a6acSopenharmony_ci	}
3266cd6a6acSopenharmony_ci
3276cd6a6acSopenharmony_ci	return rec->func_hash_all_partial_matches(rec, key, digest);
3286cd6a6acSopenharmony_ci}
3296cd6a6acSopenharmony_ci
3306cd6a6acSopenharmony_ciint selabel_lookup_best_match(struct selabel_handle *rec, char **con,
3316cd6a6acSopenharmony_ci			      const char *key, const char **aliases, int type)
3326cd6a6acSopenharmony_ci{
3336cd6a6acSopenharmony_ci	struct selabel_lookup_rec *lr;
3346cd6a6acSopenharmony_ci
3356cd6a6acSopenharmony_ci	if (!rec->func_lookup_best_match) {
3366cd6a6acSopenharmony_ci		errno = ENOTSUP;
3376cd6a6acSopenharmony_ci		return -1;
3386cd6a6acSopenharmony_ci	}
3396cd6a6acSopenharmony_ci
3406cd6a6acSopenharmony_ci	lr = selabel_lookup_bm_common(rec, 1, key, type, aliases);
3416cd6a6acSopenharmony_ci	if (!lr)
3426cd6a6acSopenharmony_ci		return -1;
3436cd6a6acSopenharmony_ci
3446cd6a6acSopenharmony_ci	*con = strdup(lr->ctx_trans);
3456cd6a6acSopenharmony_ci	return *con ? 0 : -1;
3466cd6a6acSopenharmony_ci}
3476cd6a6acSopenharmony_ci
3486cd6a6acSopenharmony_ciint selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
3496cd6a6acSopenharmony_ci			      const char *key, const char **aliases, int type)
3506cd6a6acSopenharmony_ci{
3516cd6a6acSopenharmony_ci	struct selabel_lookup_rec *lr;
3526cd6a6acSopenharmony_ci
3536cd6a6acSopenharmony_ci	if (!rec->func_lookup_best_match) {
3546cd6a6acSopenharmony_ci		errno = ENOTSUP;
3556cd6a6acSopenharmony_ci		return -1;
3566cd6a6acSopenharmony_ci	}
3576cd6a6acSopenharmony_ci
3586cd6a6acSopenharmony_ci	lr = selabel_lookup_bm_common(rec, 0, key, type, aliases);
3596cd6a6acSopenharmony_ci	if (!lr)
3606cd6a6acSopenharmony_ci		return -1;
3616cd6a6acSopenharmony_ci
3626cd6a6acSopenharmony_ci	*con = strdup(lr->ctx_raw);
3636cd6a6acSopenharmony_ci	return *con ? 0 : -1;
3646cd6a6acSopenharmony_ci}
3656cd6a6acSopenharmony_ci
3666cd6a6acSopenharmony_cienum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
3676cd6a6acSopenharmony_ci				    struct selabel_handle *h2)
3686cd6a6acSopenharmony_ci{
3696cd6a6acSopenharmony_ci	if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
3706cd6a6acSopenharmony_ci		return SELABEL_INCOMPARABLE;
3716cd6a6acSopenharmony_ci
3726cd6a6acSopenharmony_ci	return h1->func_cmp(h1, h2);
3736cd6a6acSopenharmony_ci}
3746cd6a6acSopenharmony_ci
3756cd6a6acSopenharmony_ciint selabel_digest(struct selabel_handle *rec,
3766cd6a6acSopenharmony_ci				    unsigned char **digest, size_t *digest_len,
3776cd6a6acSopenharmony_ci				    char ***specfiles, size_t *num_specfiles)
3786cd6a6acSopenharmony_ci{
3796cd6a6acSopenharmony_ci	if (!rec->digest) {
3806cd6a6acSopenharmony_ci		errno = EINVAL;
3816cd6a6acSopenharmony_ci		return -1;
3826cd6a6acSopenharmony_ci	}
3836cd6a6acSopenharmony_ci
3846cd6a6acSopenharmony_ci	*digest = rec->digest->digest;
3856cd6a6acSopenharmony_ci	*digest_len = DIGEST_SPECFILE_SIZE;
3866cd6a6acSopenharmony_ci	*specfiles = rec->digest->specfile_list;
3876cd6a6acSopenharmony_ci	*num_specfiles = rec->digest->specfile_cnt;
3886cd6a6acSopenharmony_ci	return 0;
3896cd6a6acSopenharmony_ci}
3906cd6a6acSopenharmony_ci
3916cd6a6acSopenharmony_civoid selabel_close(struct selabel_handle *rec)
3926cd6a6acSopenharmony_ci{
3936cd6a6acSopenharmony_ci	if (rec->digest)
3946cd6a6acSopenharmony_ci		selabel_digest_fini(rec->digest);
3956cd6a6acSopenharmony_ci	rec->func_close(rec);
3966cd6a6acSopenharmony_ci#ifdef OHOS_FC_INIT
3976cd6a6acSopenharmony_ci	free_spec_files(rec);
3986cd6a6acSopenharmony_ci#else
3996cd6a6acSopenharmony_ci	free(rec->spec_file);
4006cd6a6acSopenharmony_ci#endif
4016cd6a6acSopenharmony_ci	free(rec);
4026cd6a6acSopenharmony_ci}
4036cd6a6acSopenharmony_ci
4046cd6a6acSopenharmony_civoid selabel_stats(struct selabel_handle *rec)
4056cd6a6acSopenharmony_ci{
4066cd6a6acSopenharmony_ci	rec->func_stats(rec);
4076cd6a6acSopenharmony_ci}
408