1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019 Joyent, Inc.
14  */
15 
16 /*
17  * varpd property management
18  */
19 
20 #include <libvarpd_impl.h>
21 #include <errno.h>
22 #include <strings.h>
23 #include <sys/mac.h>
24 #include <umem.h>
25 
26 typedef struct varpd_prop_info {
27 	varpd_impl_t		*vprop_vip;
28 	varpd_instance_t	*vprop_instance;
29 	uint_t			vprop_type;
30 	uint_t			vprop_prot;
31 	uint32_t		vprop_defsize;
32 	uint32_t		vprop_psize;
33 	char			vprop_name[LIBVARPD_PROP_NAMELEN];
34 	uint8_t			vprop_default[LIBVARPD_PROP_SIZEMAX];
35 	uint8_t			vprop_poss[LIBVARPD_PROP_SIZEMAX];
36 } varpd_prop_info_t;
37 
38 /* Internal Properties */
39 static int varpd_nintprops = 1;
40 static const char *varpd_intprops[] = {
41 	"search"
42 };
43 
44 static int
libvarpd_prop_get_search(varpd_prop_info_t * infop,void * buf,uint32_t * sizep)45 libvarpd_prop_get_search(varpd_prop_info_t *infop, void *buf, uint32_t *sizep)
46 {
47 	varpd_plugin_t *vpp = infop->vprop_instance->vri_plugin;
48 	size_t nlen;
49 
50 	nlen = strlen(vpp->vpp_name) + 1;
51 	if (nlen > *sizep)
52 		return (EOVERFLOW);
53 	*sizep = nlen;
54 	(void) strlcpy(buf, vpp->vpp_name, *sizep);
55 	return (0);
56 }
57 
58 void
libvarpd_prop_set_name(varpd_prop_handle_t * phdl,const char * name)59 libvarpd_prop_set_name(varpd_prop_handle_t *phdl, const char *name)
60 {
61 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
62 	(void) strlcpy(infop->vprop_name, name, OVERLAY_PROP_NAMELEN);
63 }
64 
65 void
libvarpd_prop_set_prot(varpd_prop_handle_t * phdl,overlay_prop_prot_t perm)66 libvarpd_prop_set_prot(varpd_prop_handle_t *phdl, overlay_prop_prot_t perm)
67 {
68 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
69 	infop->vprop_prot = perm;
70 }
71 
72 void
libvarpd_prop_set_type(varpd_prop_handle_t * phdl,overlay_prop_type_t type)73 libvarpd_prop_set_type(varpd_prop_handle_t *phdl, overlay_prop_type_t type)
74 {
75 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
76 	infop->vprop_type = type;
77 }
78 
79 int
libvarpd_prop_set_default(varpd_prop_handle_t * phdl,void * buf,ssize_t len)80 libvarpd_prop_set_default(varpd_prop_handle_t *phdl, void *buf, ssize_t len)
81 {
82 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
83 
84 	if (len > LIBVARPD_PROP_SIZEMAX)
85 		return (E2BIG);
86 
87 	if (len < 0)
88 		return (EOVERFLOW);
89 
90 	bcopy(buf, infop->vprop_default, len);
91 	infop->vprop_defsize = len;
92 	return (0);
93 }
94 
95 void
libvarpd_prop_set_nodefault(varpd_prop_handle_t * phdl)96 libvarpd_prop_set_nodefault(varpd_prop_handle_t *phdl)
97 {
98 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
99 
100 	infop->vprop_default[0] = '\0';
101 	infop->vprop_defsize = 0;
102 }
103 
104 void
libvarpd_prop_set_range_uint32(varpd_prop_handle_t * phdl,uint32_t min,uint32_t max)105 libvarpd_prop_set_range_uint32(varpd_prop_handle_t *phdl, uint32_t min,
106     uint32_t max)
107 {
108 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
109 	mac_propval_range_t *rangep = (mac_propval_range_t *)infop->vprop_poss;
110 
111 	if (rangep->mpr_count != 0 && rangep->mpr_type != MAC_PROPVAL_UINT32)
112 		return;
113 
114 	if (infop->vprop_psize + sizeof (mac_propval_uint32_range_t) >
115 	    sizeof (infop->vprop_poss))
116 		return;
117 
118 	infop->vprop_psize += sizeof (mac_propval_uint32_range_t);
119 	rangep->mpr_count++;
120 	rangep->mpr_type = MAC_PROPVAL_UINT32;
121 	rangep->u.mpr_uint32[rangep->mpr_count-1].mpur_min = min;
122 	rangep->u.mpr_uint32[rangep->mpr_count-1].mpur_max = max;
123 }
124 
125 void
libvarpd_prop_set_range_str(varpd_prop_handle_t * phdl,const char * str)126 libvarpd_prop_set_range_str(varpd_prop_handle_t *phdl, const char *str)
127 {
128 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
129 	size_t len = strlen(str) + 1; /* Account for a null terminator */
130 	mac_propval_range_t *rangep = (mac_propval_range_t *)infop->vprop_poss;
131 	mac_propval_str_range_t *pstr = &rangep->u.mpr_str;
132 
133 	if (rangep->mpr_count != 0 && rangep->mpr_type != MAC_PROPVAL_STR)
134 		return;
135 
136 	if (infop->vprop_psize + len > sizeof (infop->vprop_poss))
137 		return;
138 
139 	rangep->mpr_count++;
140 	rangep->mpr_type = MAC_PROPVAL_STR;
141 	(void) strlcpy((char *)&pstr->mpur_data[pstr->mpur_nextbyte], str,
142 	    sizeof (infop->vprop_poss) - infop->vprop_psize);
143 	pstr->mpur_nextbyte += len;
144 	infop->vprop_psize += len;
145 }
146 
147 int
libvarpd_prop_handle_alloc(varpd_handle_t * vph,varpd_instance_handle_t * inst,varpd_prop_handle_t ** phdlp)148 libvarpd_prop_handle_alloc(varpd_handle_t *vph, varpd_instance_handle_t *inst,
149     varpd_prop_handle_t **phdlp)
150 {
151 	varpd_prop_info_t *infop;
152 
153 	infop = umem_alloc(sizeof (varpd_prop_info_t), UMEM_DEFAULT);
154 	if (infop == NULL)
155 		return (ENOMEM);
156 
157 	bzero(infop, sizeof (varpd_prop_info_t));
158 	infop->vprop_vip = (varpd_impl_t *)vph;
159 	infop->vprop_instance = (varpd_instance_t *)inst;
160 
161 	*phdlp = (varpd_prop_handle_t *)infop;
162 	return (0);
163 }
164 
165 void
libvarpd_prop_handle_free(varpd_prop_handle_t * phdl)166 libvarpd_prop_handle_free(varpd_prop_handle_t *phdl)
167 {
168 	umem_free(phdl, sizeof (varpd_prop_info_t));
169 }
170 
171 int
libvarpd_prop_nprops(varpd_instance_handle_t * ihdl,uint_t * np)172 libvarpd_prop_nprops(varpd_instance_handle_t *ihdl, uint_t *np)
173 {
174 	int ret;
175 	varpd_instance_t *instp = (varpd_instance_t *)ihdl;
176 
177 	ret = instp->vri_plugin->vpp_ops->vpo_nprops(instp->vri_private, np);
178 	if (ret != 0)
179 		return (ret);
180 	*np += varpd_nintprops;
181 	return (0);
182 }
183 
184 static int
libvarpd_prop_info_fill_int_cb(varpd_handle_t * handle,const char * name,void * arg)185 libvarpd_prop_info_fill_int_cb(varpd_handle_t *handle, const char *name,
186     void *arg)
187 {
188 	varpd_prop_handle_t *vph = arg;
189 	libvarpd_prop_set_range_str(vph, name);
190 	return (0);
191 }
192 
193 static int
libvarpd_prop_info_fill_int(varpd_prop_handle_t * vph,uint_t propid)194 libvarpd_prop_info_fill_int(varpd_prop_handle_t *vph, uint_t propid)
195 {
196 	varpd_prop_info_t *infop = (varpd_prop_info_t *)vph;
197 	if (propid >= varpd_nintprops)
198 		abort();
199 	libvarpd_prop_set_name(vph, varpd_intprops[0]);
200 	libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_READ);
201 	libvarpd_prop_set_type(vph, OVERLAY_PROP_T_STRING);
202 	libvarpd_prop_set_nodefault(vph);
203 	(void) libvarpd_plugin_walk(
204 	    (varpd_handle_t *)infop->vprop_instance->vri_impl,
205 	    libvarpd_prop_info_fill_int_cb, vph);
206 	return (0);
207 }
208 
209 int
libvarpd_prop_info_fill(varpd_prop_handle_t * phdl,uint_t propid)210 libvarpd_prop_info_fill(varpd_prop_handle_t *phdl, uint_t propid)
211 {
212 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
213 	varpd_instance_t *instp = infop->vprop_instance;
214 	mac_propval_range_t *rangep = (mac_propval_range_t *)infop->vprop_poss;
215 
216 	infop->vprop_psize = sizeof (mac_propval_range_t);
217 
218 	bzero(rangep, sizeof (mac_propval_range_t));
219 	if (propid < varpd_nintprops) {
220 		return (libvarpd_prop_info_fill_int(phdl, propid));
221 	} else {
222 		varpd_plugin_t *vpp = instp->vri_plugin;
223 		return (vpp->vpp_ops->vpo_propinfo(instp->vri_private,
224 		    propid - varpd_nintprops, phdl));
225 	}
226 }
227 
228 int
libvarpd_prop_info(varpd_prop_handle_t * phdl,const char ** namep,uint_t * typep,uint_t * protp,const void ** defp,uint32_t * sizep,const mac_propval_range_t ** possp)229 libvarpd_prop_info(varpd_prop_handle_t *phdl, const char **namep,
230     uint_t *typep, uint_t *protp, const void **defp, uint32_t *sizep,
231     const mac_propval_range_t **possp)
232 {
233 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
234 	if (namep != NULL)
235 		*namep = infop->vprop_name;
236 	if (typep != NULL)
237 		*typep = infop->vprop_type;
238 	if (protp != NULL)
239 		*protp = infop->vprop_prot;
240 	if (defp != NULL)
241 		*defp = infop->vprop_default;
242 	if (sizep != NULL)
243 		*sizep = infop->vprop_psize;
244 	if (possp != NULL)
245 		*possp = (mac_propval_range_t *)infop->vprop_poss;
246 	return (0);
247 }
248 
249 int
libvarpd_prop_get(varpd_prop_handle_t * phdl,void * buf,uint32_t * sizep)250 libvarpd_prop_get(varpd_prop_handle_t *phdl, void *buf, uint32_t *sizep)
251 {
252 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
253 	varpd_instance_t *instp = infop->vprop_instance;
254 
255 	if (infop->vprop_name[0] == '\0')
256 		return (EINVAL);
257 
258 	if (strcmp(varpd_intprops[0], infop->vprop_name) == 0) {
259 		/* search property */
260 		return (libvarpd_prop_get_search(infop, buf, sizep));
261 	}
262 
263 	return (instp->vri_plugin->vpp_ops->vpo_getprop(instp->vri_private,
264 	    infop->vprop_name, buf, sizep));
265 }
266 
267 int
libvarpd_prop_set(varpd_prop_handle_t * phdl,const void * buf,uint32_t size)268 libvarpd_prop_set(varpd_prop_handle_t *phdl, const void *buf, uint32_t size)
269 {
270 	int i;
271 	varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
272 	varpd_instance_t *instp = infop->vprop_instance;
273 
274 	if (infop->vprop_name[0] == '\0')
275 		return (EINVAL);
276 
277 	for (i = 0; i < varpd_nintprops; i++) {
278 		if (strcmp(infop->vprop_name, varpd_intprops[i]) == 0) {
279 			return (EPERM);
280 		}
281 	}
282 
283 	return (instp->vri_plugin->vpp_ops->vpo_setprop(instp->vri_private,
284 	    infop->vprop_name, buf, size));
285 }
286 
287 void
libvarpd_prop_door_convert(const varpd_prop_handle_t * phdl,varpd_client_propinfo_arg_t * vcfap)288 libvarpd_prop_door_convert(const varpd_prop_handle_t *phdl,
289     varpd_client_propinfo_arg_t *vcfap)
290 {
291 	const varpd_prop_info_t *infop = (const varpd_prop_info_t *)phdl;
292 
293 	vcfap->vcfa_type = infop->vprop_type;
294 	vcfap->vcfa_prot = infop->vprop_prot;
295 	vcfap->vcfa_defsize = infop->vprop_defsize;
296 	vcfap->vcfa_psize = infop->vprop_psize;
297 	bcopy(infop->vprop_name, vcfap->vcfa_name, LIBVARPD_PROP_NAMELEN);
298 	bcopy(infop->vprop_default, vcfap->vcfa_default, LIBVARPD_PROP_SIZEMAX);
299 	bcopy(infop->vprop_poss, vcfap->vcfa_poss, LIBVARPD_PROP_SIZEMAX);
300 }
301