1/*
2 * Generalized labeling frontend for userspace object managers.
3 *
4 * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
5 */
6
7#include <sys/types.h>
8#include <ctype.h>
9#include <errno.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <selinux/selinux.h>
14#include "callbacks.h"
15#include "label_internal.h"
16
17#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
18
19typedef int (*selabel_initfunc)(struct selabel_handle *rec,
20				const struct selinux_opt *opts,
21				unsigned nopts);
22
23static selabel_initfunc initfuncs[] = {
24	&selabel_file_init,
25	NULL,
26	NULL,
27	NULL,
28	&selabel_property_init,
29};
30
31/*
32 * Validation functions
33 */
34
35static inline int selabel_is_validate_set(const struct selinux_opt *opts,
36					  unsigned n)
37{
38	while (n--)
39		if (opts[n].type == SELABEL_OPT_VALIDATE)
40			return !!opts[n].value;
41
42	return 0;
43}
44
45int selabel_validate(struct selabel_handle *rec,
46		     struct selabel_lookup_rec *contexts)
47{
48	int rc = 0;
49
50	if (!rec->validating || contexts->validated)
51		goto out;
52
53	rc = selinux_validate(&contexts->ctx_raw);
54	if (rc < 0)
55		goto out;
56
57	contexts->validated = 1;
58out:
59	return rc;
60}
61
62/*
63 * Public API
64 */
65
66struct selabel_handle *selabel_open(unsigned int backend,
67				    const struct selinux_opt *opts,
68				    unsigned nopts)
69{
70	struct selabel_handle *rec = NULL;
71
72	if (backend >= ARRAY_SIZE(initfuncs)) {
73		errno = EINVAL;
74		goto out;
75	}
76
77	if (initfuncs[backend] == NULL)
78		goto out;
79
80	rec = (struct selabel_handle *)malloc(sizeof(*rec));
81	if (!rec)
82		goto out;
83
84	memset(rec, 0, sizeof(*rec));
85	rec->backend = backend;
86	rec->validating = selabel_is_validate_set(opts, nopts);
87
88	if ((*initfuncs[backend])(rec, opts, nopts)) {
89		free(rec->spec_file);
90		free(rec);
91		rec = NULL;
92	}
93
94out:
95	return rec;
96}
97
98static struct selabel_lookup_rec *
99selabel_lookup_common(struct selabel_handle *rec,
100		      const char *key, int type)
101{
102	struct selabel_lookup_rec *lr;
103	lr = rec->func_lookup(rec, key, type);
104	if (!lr)
105		return NULL;
106
107	return lr;
108}
109
110int selabel_lookup(struct selabel_handle *rec, char **con,
111		   const char *key, int type)
112{
113	struct selabel_lookup_rec *lr;
114
115	lr = selabel_lookup_common(rec, key, type);
116	if (!lr)
117		return -1;
118
119	*con = strdup(lr->ctx_raw);
120	return *con ? 0 : -1;
121}
122
123bool selabel_partial_match(struct selabel_handle *rec, const char *key)
124{
125	if (!rec->func_partial_match) {
126		/*
127		 * If the label backend does not support partial matching,
128		 * then assume a match is possible.
129		 */
130		return true;
131	}
132	return rec->func_partial_match(rec, key);
133}
134
135int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
136			      const char *key, const char **aliases, int type)
137{
138	struct selabel_lookup_rec *lr;
139
140	if (!rec->func_lookup_best_match) {
141		errno = ENOTSUP;
142		return -1;
143	}
144
145	lr = rec->func_lookup_best_match(rec, key, aliases, type);
146	if (!lr)
147		return -1;
148
149	*con = strdup(lr->ctx_raw);
150	return *con ? 0 : -1;
151}
152
153enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
154				    struct selabel_handle *h2)
155{
156	if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
157		return SELABEL_INCOMPARABLE;
158
159	return h1->func_cmp(h1, h2);
160}
161
162void selabel_close(struct selabel_handle *rec)
163{
164	rec->func_close(rec);
165	free(rec->spec_file);
166	free(rec);
167}
168
169void selabel_stats(struct selabel_handle *rec)
170{
171	rec->func_stats(rec);
172}
173