1 /*
2 * Copyright 2014-2015 iXsystems, Inc.
3 * All rights reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28 #include <sys/types.h>
29 #include <mach/mach.h>
30 #include <xpc/launchd.h>
31 #include "xpc_internal.h"
32 #include <assert.h>
33
34 #define NVLIST_XPC_TYPE "__XPC_TYPE"
35
36 static void xpc2nv_primitive(nvlist_t *nv, const char *key, xpc_object_t value);
37
38 __private_extern__ void
nv_release_entry(nvlist_t * nv,const char * key)39 nv_release_entry(nvlist_t *nv, const char *key)
40 {
41 xpc_object_t tmp;
42
43 if (nvlist_exists_type(nv, key, NV_TYPE_PTR)) {
44 tmp = (void *)nvlist_take_number(nv, key);
45 xpc_release(tmp);
46 }
47 }
48
49 struct xpc_object *
nv2xpc(const nvlist_t * nv)50 nv2xpc(const nvlist_t *nv)
51 {
52 struct xpc_object *xo, *xotmp;
53 void *cookiep;
54 const char *key;
55 int type;
56 xpc_u val;
57 const nvlist_t *nvtmp;
58
59 assert(nvlist_type(nv) == NV_TYPE_NVLIST_DICTIONARY ||
60 nvlist_type(nv) == NV_TYPE_NVLIST_ARRAY);
61
62 if (nvlist_type(nv) == NV_TYPE_NVLIST_DICTIONARY)
63 xo = xpc_dictionary_create(NULL, NULL, 0);
64
65 if (nvlist_type(nv) == NV_TYPE_NVLIST_ARRAY)
66 xo = xpc_array_create(NULL, 0);
67
68 cookiep = NULL;
69 while ((key = nvlist_next(nv, &type, &cookiep)) != NULL) {
70 xotmp = NULL;
71
72 switch (type) {
73 case NV_TYPE_BOOL:
74 val.b = nvlist_get_bool(nv, key);
75 xotmp = xpc_bool_create(val.b);
76 break;
77
78 case NV_TYPE_STRING:
79 val.str = nvlist_get_string(nv, key);
80 xotmp = xpc_string_create(val.str);
81 break;
82
83 case NV_TYPE_INT64:
84 val.i = nvlist_get_int64(nv, key);
85 xotmp = xpc_int64_create(val.i);
86 break;
87
88 case NV_TYPE_UINT64:
89 val.ui = nvlist_get_uint64(nv, key);
90 xotmp = xpc_uint64_create(val.ui);
91 break;
92
93 case NV_TYPE_DESCRIPTOR:
94 val.fd = nvlist_get_descriptor(nv, key);
95 xotmp = _xpc_prim_create(_XPC_TYPE_FD, val, 0);
96 break;
97
98 case NV_TYPE_PTR:
99 break;
100
101 case NV_TYPE_BINARY:
102 break;
103
104 case NV_TYPE_UUID:
105 memcpy(&val.uuid, nvlist_get_uuid(nv, key),
106 sizeof(uuid_t));
107 xotmp = _xpc_prim_create(_XPC_TYPE_UUID, val, 0);
108
109 case NV_TYPE_NVLIST_ARRAY:
110 nvtmp = nvlist_get_nvlist_array(nv, key);
111 xotmp = nv2xpc(nvtmp);
112 break;
113
114 case NV_TYPE_NVLIST_DICTIONARY:
115 nvtmp = nvlist_get_nvlist_dictionary(nv, key);
116 xotmp = nv2xpc(nvtmp);
117 break;
118 }
119
120 if (xotmp) {
121 if (nvlist_type(nv) == NV_TYPE_NVLIST_DICTIONARY)
122 xpc_dictionary_set_value(xo, key, xotmp);
123
124 if (nvlist_type(nv) == NV_TYPE_NVLIST_ARRAY)
125 xpc_array_append_value(xo, xotmp);
126 }
127 }
128
129 return (xo);
130 }
131
132 static void
xpc2nv_primitive(nvlist_t * nv,const char * key,xpc_object_t value)133 xpc2nv_primitive(nvlist_t *nv, const char *key, xpc_object_t value)
134 {
135 struct xpc_object *xotmp = value;
136
137 switch (xotmp->xo_xpc_type) {
138 case _XPC_TYPE_DICTIONARY:
139 nvlist_add_nvlist_dictionary(nv, key, xpc2nv(xotmp));
140 break;
141
142 case _XPC_TYPE_ARRAY:
143 nvlist_add_nvlist_array(nv, key, xpc2nv(xotmp));
144 break;
145
146 case _XPC_TYPE_BOOL:
147 nvlist_add_bool(nv, key, xpc_bool_get_value(xotmp));
148 break;
149
150 case _XPC_TYPE_CONNECTION:
151 break;
152
153 case _XPC_TYPE_ENDPOINT:
154 break;
155
156 case _XPC_TYPE_INT64:
157 nvlist_add_int64(nv, key, xpc_int64_get_value(xotmp));
158 break;
159
160 case _XPC_TYPE_UINT64:
161 nvlist_add_uint64(nv, key, xpc_uint64_get_value(xotmp));
162 break;
163
164 case _XPC_TYPE_DATE:
165 break;
166
167 case _XPC_TYPE_DATA:
168 nvlist_add_binary(nv, key,
169 xpc_data_get_bytes_ptr(xotmp),
170 xpc_data_get_length(xotmp));
171 break;
172
173 case _XPC_TYPE_STRING:
174 nvlist_add_string(nv, key,
175 xpc_string_get_string_ptr(xotmp));
176 break;
177
178 case _XPC_TYPE_UUID:
179 nvlist_add_uuid(nv, key, (uuid_t*)xpc_uuid_get_bytes(xotmp));
180 break;
181
182 case _XPC_TYPE_FD:
183 nvlist_add_descriptor(nv, key, xotmp->xo_fd);
184 break;
185
186 case _XPC_TYPE_SHMEM:
187 break;
188
189 case _XPC_TYPE_ERROR:
190 break;
191
192 case _XPC_TYPE_DOUBLE:
193 break;
194 }
195 }
196
197 nvlist_t *
xpc2nv(struct xpc_object * xo)198 xpc2nv(struct xpc_object *xo)
199 {
200 nvlist_t *nv;
201 struct xpc_object *xotmp;
202
203 if (xo->xo_xpc_type == _XPC_TYPE_DICTIONARY) {
204 nv = nvlist_create_dictionary(0);
205 printf("nv = %p\n", nv);
206 xpc_dictionary_apply(xo, ^(const char *k, xpc_object_t v) {
207 xpc2nv_primitive(nv, k, v);
208 return ((bool)true);
209 });
210 }
211
212 if (xo->xo_xpc_type == _XPC_TYPE_ARRAY) {
213 char *key;
214 nv = nvlist_create_array(0);
215 xpc_array_apply(xo, ^(size_t index, xpc_object_t v) {
216 asprintf(&key, "%ld", index);
217 xpc2nv_primitive(nv, key, v);
218 free(key);
219 return ((bool)true);
220 });
221 }
222
223 return (nv);
224 }
225
226 xpc_object_t
xpc_dictionary_create(const char * const * keys,const xpc_object_t * values,size_t count)227 xpc_dictionary_create(const char * const *keys, const xpc_object_t *values,
228 size_t count)
229 {
230 struct xpc_object *xo;
231 size_t i;
232 xpc_u val;
233
234 xo = _xpc_prim_create(_XPC_TYPE_DICTIONARY, val, count);
235
236 for (i = 0; i < count; i++)
237 xpc_dictionary_set_value(xo, keys[i], values[i]);
238
239 return (xo);
240 }
241
242 xpc_object_t
xpc_dictionary_create_reply(xpc_object_t original)243 xpc_dictionary_create_reply(xpc_object_t original)
244 {
245 struct xpc_object *xo, *xo_orig;
246 nvlist_t *nv;
247 xpc_u val;
248
249 xo_orig = original;
250 if ((xo_orig->xo_flags & _XPC_FROM_WIRE) == 0)
251 return (NULL);
252
253 return xpc_dictionary_create(NULL, NULL, 0);
254 }
255
256 void
xpc_dictionary_get_audit_token(xpc_object_t xdict,audit_token_t * token)257 xpc_dictionary_get_audit_token(xpc_object_t xdict, audit_token_t *token)
258 {
259 struct xpc_object *xo;
260
261 xo = xdict;
262 if (xo->xo_audit_token != NULL)
263 memcpy(token, xo->xo_audit_token, sizeof(*token));
264 }
265 void
xpc_dictionary_set_mach_recv(xpc_object_t xdict,const char * key,mach_port_t port)266 xpc_dictionary_set_mach_recv(xpc_object_t xdict, const char *key, mach_port_t port)
267 {
268 struct xpc_object *xo = xdict;
269 struct xpc_object *xotmp;
270 xpc_u val;
271
272 val.port = port;
273 xotmp = _xpc_prim_create(_XPC_TYPE_ENDPOINT, val, 0);
274
275 xpc_dictionary_set_value(xdict, key, xotmp);
276 }
277
278 void
xpc_dictionary_set_mach_send(xpc_object_t xdict,const char * key,mach_port_t port)279 xpc_dictionary_set_mach_send(xpc_object_t xdict, const char *key, mach_port_t port)
280 {
281 struct xpc_object *xotmp;
282 xpc_u val;
283
284 val.port = port;
285 xotmp = _xpc_prim_create(_XPC_TYPE_ENDPOINT, val, 0);
286
287 xpc_dictionary_set_value(xdict, key, xotmp);
288 }
289
290 mach_port_t
xpc_dictionary_copy_mach_send(xpc_object_t xdict,const char * key)291 xpc_dictionary_copy_mach_send(xpc_object_t xdict, const char *key)
292 {
293 struct xpc_object *xo;
294 const struct xpc_object *xotmp;
295
296 #if 0
297 xo = xdict;
298 if (nvlist_exists_type(xo->xo_nv, key, NV_TYPE_ENDPOINT))
299 return (nvlist_get_number(xo->xo_nv, key));
300 else if (nvlist_exists_binary(xo->xo_nv, key)) {
301 xotmp = (void *)nvlist_get_number(xo->xo_nv, key);
302 return (xotmp->xo_uint);
303 }
304 return (0);
305 #endif
306 }
307
308 void
xpc_dictionary_set_value(xpc_object_t xdict,const char * key,xpc_object_t value)309 xpc_dictionary_set_value(xpc_object_t xdict, const char *key, xpc_object_t value)
310 {
311 struct xpc_object *xo, *xotmp;
312 struct xpc_dict_head *head;
313 struct xpc_dict_pair *pair;
314
315 xo = xdict;
316 head = &xo->xo_dict;
317
318 TAILQ_FOREACH(pair, head, xo_link) {
319 if (!strcmp(pair->key, key)) {
320 pair->value = value;
321 return;
322 }
323 }
324
325 xo->xo_size++;
326 pair = malloc(sizeof(struct xpc_dict_pair));
327 pair->key = key;
328 pair->value = value;
329 TAILQ_INSERT_TAIL(&xo->xo_dict, pair, xo_link);
330 xpc_retain(value);
331 }
332
333 xpc_object_t
xpc_dictionary_get_value(xpc_object_t xdict,const char * key)334 xpc_dictionary_get_value(xpc_object_t xdict, const char *key)
335 {
336 struct xpc_object *xo;
337 struct xpc_dict_head *head;
338 struct xpc_dict_pair *pair;
339
340 xo = xdict;
341 head = &xo->xo_dict;
342
343 TAILQ_FOREACH(pair, head, xo_link) {
344 if (!strcmp(pair->key, key))
345 return (pair->value);
346 }
347
348 return (NULL);
349 }
350
351 size_t
xpc_dictionary_get_count(xpc_object_t xdict)352 xpc_dictionary_get_count(xpc_object_t xdict)
353 {
354 struct xpc_object *xo;
355
356 xo = xdict;
357 return (xo->xo_size);
358 }
359
360 void
xpc_dictionary_set_bool(xpc_object_t xdict,const char * key,bool value)361 xpc_dictionary_set_bool(xpc_object_t xdict, const char *key, bool value)
362 {;
363 struct xpc_object *xo, *xotmp;
364
365 xo = xdict;
366 xotmp = xpc_bool_create(value);
367 xpc_dictionary_set_value(xdict, key, xotmp);
368 }
369
370 void
xpc_dictionary_set_int64(xpc_object_t xdict,const char * key,int64_t value)371 xpc_dictionary_set_int64(xpc_object_t xdict, const char *key, int64_t value)
372 {
373 struct xpc_object *xo, *xotmp;
374
375 xo = xdict;
376 xotmp = xpc_int64_create(value);
377 xpc_dictionary_set_value(xdict, key, xotmp);
378 }
379
380 void
xpc_dictionary_set_uint64(xpc_object_t xdict,const char * key,uint64_t value)381 xpc_dictionary_set_uint64(xpc_object_t xdict, const char *key, uint64_t value)
382 {
383 struct xpc_object *xo, *xotmp;
384
385 xo = xdict;
386 xotmp = xpc_uint64_create(value);
387 xpc_dictionary_set_value(xdict, key, xotmp);
388 }
389
390 void
xpc_dictionary_set_string(xpc_object_t xdict,const char * key,const char * value)391 xpc_dictionary_set_string(xpc_object_t xdict, const char *key, const char *value)
392 {
393 struct xpc_object *xo, *xotmp;
394
395 xo = xdict;
396 xotmp = xpc_string_create(value);
397 xpc_dictionary_set_value(xdict, key, xotmp);
398 }
399
400 bool
xpc_dictionary_get_bool(xpc_object_t xdict,const char * key)401 xpc_dictionary_get_bool(xpc_object_t xdict, const char *key)
402 {
403 xpc_object_t xo;
404
405 xo = xpc_dictionary_get_value(xdict, key);
406 return (xpc_bool_get_value(xo));
407 }
408
409 int64_t
xpc_dictionary_get_int64(xpc_object_t xdict,const char * key)410 xpc_dictionary_get_int64(xpc_object_t xdict, const char *key)
411 {
412 xpc_object_t xo;
413
414 xo = xpc_dictionary_get_value(xdict, key);
415 return (xpc_int64_get_value(xo));
416 }
417
418 uint64_t
xpc_dictionary_get_uint64(xpc_object_t xdict,const char * key)419 xpc_dictionary_get_uint64(xpc_object_t xdict, const char *key)
420 {
421 xpc_object_t xo;
422
423 xo = xpc_dictionary_get_value(xdict, key);
424 return (xpc_uint64_get_value(xo));
425 }
426
427 const char *
xpc_dictionary_get_string(xpc_object_t xdict,const char * key)428 xpc_dictionary_get_string(xpc_object_t xdict, const char *key)
429 {
430 xpc_object_t xo;
431
432 xo = xpc_dictionary_get_value(xdict, key);
433 return (xpc_string_get_string_ptr(xo));
434 }
435
436 bool
xpc_dictionary_apply(xpc_object_t xdict,xpc_dictionary_applier_t applier)437 xpc_dictionary_apply(xpc_object_t xdict, xpc_dictionary_applier_t applier)
438 {
439 struct xpc_object *xo, *xotmp;
440 struct xpc_dict_head *head;
441 struct xpc_dict_pair *pair;
442
443 xo = xdict;
444 head = &xo->xo_dict;
445
446 TAILQ_FOREACH(pair, head, xo_link) {
447 if (!applier(pair->key, pair->value))
448 return (false);
449 }
450
451 return (true);
452 }
453