Merge branch 'vendor/OPENSSL'
[dragonfly.git] / sys / libprop / prop_kern.c
1 /*      $NetBSD: prop_kern.c,v 1.13 2009/10/11 12:13:45 bad Exp $       */
2
3 /*-
4  * Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <sys/types.h>
33
34 #include <libprop/proplib.h>
35
36 #if !defined(_KERNEL) && !defined(_STANDALONE)
37 #include <sys/mman.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <sys/ioctl.h>
43
44 static int
45 _prop_object_externalize_to_pref(prop_object_t obj, struct plistref *pref, char **bufp)
46 {
47         char *buf;
48
49         switch (prop_object_type(obj)) {
50         case PROP_TYPE_DICTIONARY:
51                 buf = prop_dictionary_externalize(obj);
52                 break;
53         case PROP_TYPE_ARRAY:
54                 buf = prop_array_externalize(obj);
55                 break;
56         default:
57                 return (ENOTSUP);
58         }
59         if (buf == NULL) {
60                 /* Assume we ran out of memory. */
61                 return (ENOMEM);
62         }
63         pref->pref_plist = buf;
64         pref->pref_len = strlen(buf) + 1;
65
66         *bufp = buf;
67
68         return (0);
69 }
70
71 /*
72  * prop_array_externalize_to_pref --
73  *      Externalize an array into a plistref for sending to the kernel.
74  */
75 bool
76 prop_array_externalize_to_pref(prop_array_t array, struct plistref *prefp)
77 {
78         char *buf;
79         int rv;
80
81         rv = _prop_object_externalize_to_pref(array, prefp, &buf);
82         if (rv != 0)
83                 errno = rv;     /* pass up error value in errno */
84         return (rv == 0);
85 }
86
87 /*
88  * prop_dictionary_externalize_to_pref --
89  *      Externalize an dictionary into a plistref for sending to the kernel.
90  */
91 bool
92 prop_dictionary_externalize_to_pref(prop_dictionary_t dict, struct plistref *prefp)
93 {
94         char *buf;
95         int rv;
96
97         rv = _prop_object_externalize_to_pref(dict, prefp, &buf);
98         if (rv != 0)
99                 errno = rv;     /* pass up error value in errno */
100         return (rv == 0);
101 }
102
103 static int
104 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
105 {
106         struct plistref pref;
107         char *buf;
108         int error;
109
110         error = _prop_object_externalize_to_pref(obj, &pref, &buf);
111         if (error)
112                 return (error);
113
114         if (ioctl(fd, cmd, &pref) == -1)
115                 error = errno;
116         else
117                 error = 0;
118
119         free(buf);
120
121         return (error);
122 }
123
124 /*
125  * prop_array_send_ioctl --
126  *      Send an array to the kernel using the specified ioctl.
127  */
128 int
129 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
130 {
131
132         return (_prop_object_send_ioctl(array, fd, cmd));
133 }
134
135 /*
136  * prop_dictionary_send_ioctl --
137  *      Send a dictionary to the kernel using the specified ioctl.
138  */
139 int
140 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
141 {
142
143         return (_prop_object_send_ioctl(dict, fd, cmd));
144 }
145
146 static int
147 _prop_object_internalize_from_pref(const struct plistref *pref, prop_type_t type,
148                          prop_object_t *objp)
149 {
150         prop_object_t obj = NULL;
151         char *buf;
152         int error = 0;
153
154         if (pref->pref_len == 0) {
155                 /*
156                  * This should never happen; we should always get the XML
157                  * for an empty dictionary if it's really empty.
158                  */
159                 error = EIO;
160                 goto out;
161         } else {
162                 buf = pref->pref_plist;
163                 buf[pref->pref_len - 1] = '\0'; /* extra insurance */
164                 switch (type) {
165                 case PROP_TYPE_DICTIONARY:
166                         obj = prop_dictionary_internalize(buf);
167                         break;
168                 case PROP_TYPE_ARRAY:
169                         obj = prop_array_internalize(buf);
170                         break;
171                 default:
172                         error = ENOTSUP;
173                 }
174                 (void) munmap(buf, pref->pref_len);
175                 if (obj == NULL && error == 0)
176                         error = EIO;
177         }
178
179  out:
180         if (error == 0)
181                 *objp = obj;
182         return (error);
183 }
184
185 /*
186  * prop_array_recv_ioctl --
187  *      Receive an array from the kernel using the specified ioctl.
188  */
189 int
190 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
191 {
192         struct plistref pref;
193
194         if (ioctl(fd, cmd, &pref) == -1)
195                 return (errno);
196
197         return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_ARRAY,
198                                          (prop_object_t *)arrayp));
199 }
200
201 /*
202  * prop_dictionary_recv_ioctl --
203  *      Receive a dictionary from the kernel using the specified ioctl.
204  */
205 int
206 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
207 {
208         struct plistref pref;
209
210         if (ioctl(fd, cmd, &pref) == -1)
211                 return (errno);
212
213         return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
214                                          (prop_object_t *)dictp));
215 }
216
217 /*
218  * prop_dictionary_sendrecv_ioctl --
219  *      Combination send/receive a dictionary to/from the kernel using
220  *      the specified ioctl.
221  */
222 int
223 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
224                                unsigned long cmd, prop_dictionary_t *dictp)
225 {
226         struct plistref pref;
227         char *buf;
228         int error;
229
230         error = _prop_object_externalize_to_pref(dict, &pref, &buf);
231         if (error)
232                 return (error);
233
234         if (ioctl(fd, cmd, &pref) == -1)
235                 error = errno;
236         else
237                 error = 0;
238
239         free(buf);
240
241         if (error)
242                 return (error);
243
244         return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
245                             (prop_object_t *)dictp));
246 }
247 #endif /* !_KERNEL && !_STANDALONE */
248
249 #if defined(_KERNEL)
250 #include <sys/param.h>
251 #include <sys/mman.h>
252 #include <sys/errno.h>
253 #include <sys/malloc.h>
254 #include <sys/systm.h>
255 #include <sys/proc.h>
256 #include <sys/resource.h>
257 #include <sys/objcache.h>
258 #include <sys/ioccom.h>
259 #include <vm/vm.h>
260 #include <vm/vm_extern.h>
261 #include <vm/vm_param.h>
262
263 #include "prop_object_impl.h"
264
265 /* Arbitrary limit ioctl input to 64KB */
266 unsigned int prop_object_copyin_limit = 65536;
267
268 static int
269 _prop_object_copyin(const struct plistref *pref, const prop_type_t type,
270                           prop_object_t *objp)
271 {
272         prop_object_t obj = NULL;
273         char *buf;
274         int error;
275
276         /*
277          * Allocate an extra byte so we can guarantee NUL-termination.
278          *
279          * Allow malloc to fail in case pmap would be exhausted.
280          */
281         buf = kmalloc(pref->pref_len + 1, M_TEMP, M_WAITOK);
282         if (buf == NULL)
283                 return (ENOMEM);
284         error = copyin(pref->pref_plist, buf, pref->pref_len);
285         if (error) {
286                 kfree(buf, M_TEMP);
287                 return (error);
288         }
289         buf[pref->pref_len] = '\0';
290
291         switch (type) {
292         case PROP_TYPE_ARRAY:
293                 obj = prop_array_internalize(buf);
294                 break;
295         case PROP_TYPE_DICTIONARY:
296                 obj = prop_dictionary_internalize(buf);
297                 break;
298         default:
299                 error = ENOTSUP;
300         }
301
302         kfree(buf, M_TEMP);
303         if (obj == NULL) {
304                 if (error == 0)
305                         error = EIO;
306         } else {
307                 *objp = obj;
308         }
309         return (error);
310 }
311
312
313 static int
314 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type,
315                           const u_long cmd, prop_object_t *objp)
316 {
317         if ((cmd & IOC_IN) == 0)
318                 return (EFAULT);
319
320         return _prop_object_copyin(pref, type, objp);
321 }
322
323 /*
324  * prop_array_copyin --
325  *      Copy in an array passed as a syscall arg.
326  */
327 int
328 prop_array_copyin(const struct plistref *pref, prop_array_t *arrayp)
329 {
330         return (_prop_object_copyin(pref, PROP_TYPE_ARRAY,
331                                           (prop_object_t *)arrayp));
332 }
333
334 /*
335  * prop_dictionary_copyin --
336  *      Copy in a dictionary passed as a syscall arg.
337  */
338 int
339 prop_dictionary_copyin(const struct plistref *pref, prop_dictionary_t *dictp)
340 {
341         return (_prop_object_copyin(pref, PROP_TYPE_DICTIONARY,
342                                           (prop_object_t *)dictp));
343 }
344
345
346 /*
347  * prop_array_copyin_ioctl --
348  *      Copy in an array send with an ioctl.
349  */
350 int
351 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd,
352                         prop_array_t *arrayp)
353 {
354         return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY,
355                                           cmd, (prop_object_t *)arrayp));
356 }
357
358 /*
359  * prop_dictionary_copyin_ioctl --
360  *      Copy in a dictionary sent with an ioctl.
361  */
362 int
363 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd,
364                              prop_dictionary_t *dictp)
365 {
366         return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY,
367                                           cmd, (prop_object_t *)dictp));
368 }
369
370 static int
371 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
372                            prop_object_t obj)
373 {
374         struct proc *p = curproc;
375         char *buf;
376         size_t len, rlen;
377         int error = 0;
378         vm_offset_t uaddr;
379
380         if ((cmd & IOC_OUT) == 0)
381                 return (EFAULT);
382
383         switch (prop_object_type(obj)) {
384         case PROP_TYPE_ARRAY:
385                 buf = prop_array_externalize(obj);
386                 break;
387         case PROP_TYPE_DICTIONARY:
388                 buf = prop_dictionary_externalize(obj);
389                 break;
390         default:
391                 return (ENOTSUP);
392         }
393         if (buf == NULL)
394                 return (ENOMEM);
395
396         len = strlen(buf) + 1;
397         rlen = round_page(len);
398
399         /*
400          * See sys_mmap() in sys/uvm/uvm_mmap.c.
401          * Let's act as if we were calling mmap(0, ...)
402          */
403 #if 0
404         uaddr = p->p_emul->e_vm_default_addr(p,
405             (vaddr_t)p->p_vmspace->vm_daddr, rlen);
406 #endif
407         uaddr = round_page((vm_offset_t)p->p_vmspace->vm_daddr + maxdsiz);
408
409         error = vm_mmap(&p->p_vmspace->vm_map,
410                          &uaddr, rlen,
411                          VM_PROT_READ|VM_PROT_WRITE,
412                          VM_PROT_READ|VM_PROT_WRITE,
413                          MAP_PRIVATE|MAP_ANON,
414                          NULL, 0);
415         if (error == 0) {
416                 error = copyout(buf, (char *)uaddr, len);
417                 if (error == 0) {
418                         pref->pref_plist = (char *)uaddr;
419                         pref->pref_len   = len;
420                 }
421         }
422
423         kfree(buf, M_TEMP);
424
425         return (error);
426 }
427
428 /*
429  * prop_array_copyout_ioctl --
430  *      Copy out an array being received with an ioctl.
431  */
432 int
433 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd,
434                          prop_array_t array)
435 {
436         return (_prop_object_copyout_ioctl(pref, cmd, array));
437 }
438
439 /*
440  * prop_dictionary_copyout_ioctl --
441  *      Copy out a dictionary being received with an ioctl.
442  */
443 int
444 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
445                               prop_dictionary_t dict)
446 {
447         return (_prop_object_copyout_ioctl(pref, cmd, dict));
448 }
449 #endif /* _KERNEL */