]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurityd/lib/sec_xdr.c
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / libsecurityd / lib / sec_xdr.c
1 /*
2 * Copyright (c) 2006,2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <string.h>
25 #include <stdlib.h>
26 #include <security_utilities/simulatecrash_assert.h>
27
28 #include "sec_xdr.h"
29
30 #define ALIGNMENT sizeof(void*)
31 #define ALIGNUP(LEN) (((LEN - 1) & ~(ALIGNMENT - 1)) + ALIGNMENT)
32
33 /*
34 * XDR counted bytes
35 * *cpp is a pointer to the bytes, *sizep is the count.
36 * If *cpp is NULL maxsize bytes are allocated
37 */
38 bool_t sec_xdr_bytes(XDR *xdrs, uint8_t **cpp, u_int *sizep, u_int maxsize)
39 {
40 uint8_t *sp = cpp ? *cpp : NULL; /* sp is the actual string pointer */
41 u_int nodesize = sizep ? *sizep : 0;
42
43 /*
44 * first deal with the length since xdr bytes are counted
45 */
46 if (! xdr_u_int(xdrs, &nodesize))
47 return (FALSE);
48
49 if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE))
50 return (FALSE);
51
52 if (sizep && (xdrs->x_op == XDR_DECODE))
53 *sizep = nodesize;
54
55 bool_t sizeof_alloc = sec_xdr_arena_size_allocator(xdrs);
56
57 /*
58 * now deal with the actual bytes
59 */
60 switch (xdrs->x_op) {
61 case XDR_DECODE:
62 if (nodesize == 0)
63 return (TRUE);
64 if (!sp) {
65 if (!sec_mem_alloc(xdrs, nodesize, &sp))
66 return (FALSE);
67 if (!sizeof_alloc && cpp != NULL)
68 *cpp = sp; /* sp can be NULL when counting required space */
69 }
70 /* FALLTHROUGH */
71 case XDR_ENCODE:
72 return (xdr_opaque(xdrs, (char *)sp, nodesize));
73
74 case XDR_FREE:
75 if (sp != NULL) {
76 sec_mem_free(xdrs, sp, nodesize);
77 *cpp = NULL;
78 }
79 return (TRUE);
80 }
81 /* NOTREACHED */
82 return (FALSE);
83 }
84
85 bool_t sec_xdr_charp(XDR *xdrs, char **cpp, u_int maxsize)
86 {
87 char *sp = cpp ? *cpp : NULL; /* sp is the actual string pointer */
88 u_int size = 0;
89
90 switch (xdrs->x_op) {
91 case XDR_FREE:
92 if (sp == NULL) return(TRUE); /* already free */
93 sec_mem_free(xdrs, sp, size);
94 *cpp = NULL;
95 return (TRUE);
96 case XDR_ENCODE:
97 if (sp) size = (u_int)(strlen(sp) + 1);
98 /* FALLTHROUGH */
99 case XDR_DECODE:
100 return sec_xdr_bytes(xdrs, (uint8_t**)cpp, &size, maxsize);
101 }
102 /* NOTREACHED */
103 return (FALSE);
104 }
105
106 bool_t sec_mem_alloc(XDR *xdr, u_int bsize, uint8_t **data)
107 {
108 if (!xdr || !data)
109 return (FALSE);
110
111 assert(xdr->x_op == XDR_DECODE);
112
113 sec_xdr_arena_allocator_t *allocator = sec_xdr_arena_allocator(xdr);
114 if (allocator) {
115 if (*data != NULL)
116 return (TRUE); // no allocation needed
117 size_t bytes_left;
118 switch(allocator->magic) {
119 case xdr_arena_magic:
120 bytes_left = allocator->end - allocator->offset;
121 if (bsize > bytes_left)
122 return (FALSE);
123 else {
124 uint8_t *temp = allocator->offset;
125 allocator->offset += bsize;
126 *data = temp;
127 return (TRUE);
128 }
129 case xdr_size_magic:
130 allocator->offset = (uint8_t*)((size_t)allocator->offset + bsize);
131 return (TRUE);
132 }
133 }
134
135 void *alloc = calloc(1, bsize);
136 if (!alloc)
137 return (FALSE);
138
139 *data = alloc;
140 return (TRUE);
141 }
142
143 void sec_mem_free(XDR *xdr, void *ptr, u_int bsize)
144 {
145 if (sec_xdr_arena_allocator(xdr))
146 return;
147
148 return free(ptr);
149 }
150
151 static const sec_xdr_arena_allocator_t size_alloc = { xdr_size_magic, 0, 0, 0 };
152 void sec_xdr_arena_init_size_alloc(sec_xdr_arena_allocator_t *arena, XDR *xdr)
153 {
154 memcpy(arena, &size_alloc, sizeof(size_alloc));
155 xdr->x_public = (char *)arena;
156 }
157
158 bool_t sec_xdr_arena_init(sec_xdr_arena_allocator_t *arena, XDR *xdr,
159 size_t in_length, uint8_t *in_data)
160 {
161 if (!xdr)
162 return FALSE;
163 uint8_t *data = in_data ? in_data : calloc(1, ALIGNUP(in_length));
164 if (!data)
165 return FALSE;
166 arena->magic = xdr_arena_magic;
167 arena->offset = data;
168 arena->data = data;
169 arena->end = data + in_length;
170 xdr->x_public = (void*)arena;
171 return TRUE;
172 }
173
174 void sec_xdr_arena_free(sec_xdr_arena_allocator_t *arena,
175 void *ptr, size_t bsize)
176 {
177 assert(arena->magic == xdr_arena_magic);
178 free(arena->data);
179 }
180
181 void *sec_xdr_arena_data(sec_xdr_arena_allocator_t *arena)
182 {
183 if (arena)
184 return arena->data;
185
186 return NULL;
187 }
188
189 sec_xdr_arena_allocator_t *sec_xdr_arena_allocator(XDR *xdr)
190 {
191 sec_xdr_arena_allocator_t *allocator = xdr ? (sec_xdr_arena_allocator_t *)xdr->x_public : NULL;
192
193 if (allocator &&
194 (allocator->magic == xdr_arena_magic ||
195 allocator->magic == xdr_size_magic))
196 return allocator;
197
198 return NULL;
199 }
200
201 bool_t sec_xdr_arena_size_allocator(XDR *xdr)
202 {
203 sec_xdr_arena_allocator_t *allocator = xdr ? (sec_xdr_arena_allocator_t *)xdr->x_public : NULL;
204 if (allocator && (allocator->magic == xdr_size_magic))
205 return TRUE;
206
207 return FALSE;
208 }
209
210
211 bool_t copyin(void *data, xdrproc_t proc, void** copy, u_int *size)
212 {
213 if (!copy)
214 return (FALSE);
215
216 // xdr_sizeof is illbehaved
217 u_int length = sec_xdr_sizeof_in(proc, data);
218 uint8_t *xdr_data = malloc(length);
219 if (!xdr_data)
220 return (FALSE);
221
222 XDR xdr;
223 sec_xdrmem_create(&xdr, (char *)xdr_data, length, XDR_ENCODE);
224
225 // cast to void* - function can go both ways (xdr->x_op)
226 if (proc(&xdr, data, 0)) {
227 *copy = xdr_data;
228 if (size) *size = length;
229 return (TRUE);
230 }
231
232 free(xdr_data);
233 return (FALSE);
234 }
235
236 // Unmarshall xdr data and return pointer to single allocation containing data
237 // Generally use *_PTR for xdrproc_t taking an objp that matches data's type
238 // ie. xdr_CSSM_POSSIBLY_KEY_IN_DATA_PTR(XDR *xdrs, CSSM_DATA_PTR *objp)
239 // with data matching objp
240 // If you pass in length pointing to a non-zero value, data will be assumed
241 // to have pre-allocated space for use by copyout in that amount.
242 // If *data is not NULL it will be assumed to be allocated already.
243 bool_t copyout(const void *copy, u_int size, xdrproc_t proc, void **data, u_int *length)
244 {
245
246 if (!data || (size > ~(u_int)0))
247 return (FALSE);
248
249 XDR xdr;
250 sec_xdrmem_create(&xdr, (void *)copy, size, XDR_DECODE);
251
252 u_int length_required = sec_xdr_sizeof_out(copy, size, proc, data);
253 u_int length_out = length ? *length : 0;
254
255 if (length_out && (length_required > length_out))
256 return (FALSE);
257
258 bool_t passed_in_data = (*data && length_out);
259 sec_xdr_arena_allocator_t arena;
260 // set up arena with memory passed in (length_out > 0) or ask to allocate
261 if (!sec_xdr_arena_init(&arena, &xdr, length_out ? length_out : length_required, length_out ? *data : NULL))
262 return (FALSE);
263
264 if (proc(&xdr, data, 0))
265 {
266 if(length) {
267 *length = length_required;
268 }
269 return (TRUE);
270 }
271
272 if (!passed_in_data)
273 sec_xdr_arena_free(sec_xdr_arena_allocator(&xdr), NULL, 0);
274 return (FALSE);
275 }
276
277 // unmarshall xdr data and return pointer to individual allocations containing data
278 // only use *_PTR for xdrproc_ts and pointers for data
279 bool_t copyout_chunked(const void *copy, u_int size, xdrproc_t proc, void **data)
280 {
281 if (!data || (size > ~(u_int)0))
282 return (FALSE);
283
284 XDR xdr;
285 sec_xdrmem_create(&xdr, (void *)copy, size, XDR_DECODE);
286
287 void *data_out = NULL;
288
289 if (proc(&xdr, &data_out, 0))
290 {
291 *data = data_out;
292 return (TRUE);
293 }
294 return (FALSE);
295 }