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);
90		rec = NULL;
91	}
92
93out:
94	return rec;
95}
96
97static struct selabel_lookup_rec *
98selabel_lookup_common(struct selabel_handle *rec,
99		      const char *key, int type)
100{
101	struct selabel_lookup_rec *lr;
102	lr = rec->func_lookup(rec, key, type);
103	if (!lr)
104		return NULL;
105
106	return lr;
107}
108
109int selabel_lookup(struct selabel_handle *rec, char **con,
110		   const char *key, int type)
111{
112	struct selabel_lookup_rec *lr;
113
114	lr = selabel_lookup_common(rec, key, type);
115	if (!lr)
116		return -1;
117
118	*con = strdup(lr->ctx_raw);
119	return *con ? 0 : -1;
120}
121
122bool selabel_partial_match(struct selabel_handle *rec, const char *key)
123{
124	if (!rec->func_partial_match) {
125		/*
126		 * If the label backend does not support partial matching,
127		 * then assume a match is possible.
128		 */
129		return true;
130	}
131	return rec->func_partial_match(rec, key);
132}
133
134int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
135			      const char *key, const char **aliases, int type)
136{
137	struct selabel_lookup_rec *lr;
138
139	if (!rec->func_lookup_best_match) {
140		errno = ENOTSUP;
141		return -1;
142	}
143
144	lr = rec->func_lookup_best_match(rec, key, aliases, type);
145	if (!lr)
146		return -1;
147
148	*con = strdup(lr->ctx_raw);
149	return *con ? 0 : -1;
150}
151
152void selabel_close(struct selabel_handle *rec)
153{
154	rec->func_close(rec);
155	free(rec);
156}
157
158void selabel_stats(struct selabel_handle *rec)
159{
160	rec->func_stats(rec);
161}
162