1 |
|
|
/* $OpenBSD: asn1_lib.c,v 1.39 2017/05/02 03:59:44 deraadt Exp $ */ |
2 |
|
|
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 |
|
|
* All rights reserved. |
4 |
|
|
* |
5 |
|
|
* This package is an SSL implementation written |
6 |
|
|
* by Eric Young (eay@cryptsoft.com). |
7 |
|
|
* The implementation was written so as to conform with Netscapes SSL. |
8 |
|
|
* |
9 |
|
|
* This library is free for commercial and non-commercial use as long as |
10 |
|
|
* the following conditions are aheared to. The following conditions |
11 |
|
|
* apply to all code found in this distribution, be it the RC4, RSA, |
12 |
|
|
* lhash, DES, etc., code; not just the SSL code. The SSL documentation |
13 |
|
|
* included with this distribution is covered by the same copyright terms |
14 |
|
|
* except that the holder is Tim Hudson (tjh@cryptsoft.com). |
15 |
|
|
* |
16 |
|
|
* Copyright remains Eric Young's, and as such any Copyright notices in |
17 |
|
|
* the code are not to be removed. |
18 |
|
|
* If this package is used in a product, Eric Young should be given attribution |
19 |
|
|
* as the author of the parts of the library used. |
20 |
|
|
* This can be in the form of a textual message at program startup or |
21 |
|
|
* in documentation (online or textual) provided with the package. |
22 |
|
|
* |
23 |
|
|
* Redistribution and use in source and binary forms, with or without |
24 |
|
|
* modification, are permitted provided that the following conditions |
25 |
|
|
* are met: |
26 |
|
|
* 1. Redistributions of source code must retain the copyright |
27 |
|
|
* notice, this list of conditions and the following disclaimer. |
28 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
29 |
|
|
* notice, this list of conditions and the following disclaimer in the |
30 |
|
|
* documentation and/or other materials provided with the distribution. |
31 |
|
|
* 3. All advertising materials mentioning features or use of this software |
32 |
|
|
* must display the following acknowledgement: |
33 |
|
|
* "This product includes cryptographic software written by |
34 |
|
|
* Eric Young (eay@cryptsoft.com)" |
35 |
|
|
* The word 'cryptographic' can be left out if the rouines from the library |
36 |
|
|
* being used are not cryptographic related :-). |
37 |
|
|
* 4. If you include any Windows specific code (or a derivative thereof) from |
38 |
|
|
* the apps directory (application code) you must include an acknowledgement: |
39 |
|
|
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
40 |
|
|
* |
41 |
|
|
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
42 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
43 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
44 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
45 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
46 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
47 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
48 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
49 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
50 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
51 |
|
|
* SUCH DAMAGE. |
52 |
|
|
* |
53 |
|
|
* The licence and distribution terms for any publically available version or |
54 |
|
|
* derivative of this code cannot be changed. i.e. this code cannot simply be |
55 |
|
|
* copied and put under another distribution licence |
56 |
|
|
* [including the GNU Public Licence.] |
57 |
|
|
*/ |
58 |
|
|
|
59 |
|
|
#include <limits.h> |
60 |
|
|
#include <stdio.h> |
61 |
|
|
#include <string.h> |
62 |
|
|
|
63 |
|
|
#include <openssl/asn1.h> |
64 |
|
|
#include <openssl/err.h> |
65 |
|
|
|
66 |
|
|
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, int max); |
67 |
|
|
static void asn1_put_length(unsigned char **pp, int length); |
68 |
|
|
|
69 |
|
|
static int |
70 |
|
|
_asn1_check_infinite_end(const unsigned char **p, long len) |
71 |
|
|
{ |
72 |
|
|
/* If there is 0 or 1 byte left, the length check should pick |
73 |
|
|
* things up */ |
74 |
|
|
if (len <= 0) |
75 |
|
|
return (1); |
76 |
|
|
else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) { |
77 |
|
|
(*p) += 2; |
78 |
|
|
return (1); |
79 |
|
|
} |
80 |
|
|
return (0); |
81 |
|
|
} |
82 |
|
|
|
83 |
|
|
int |
84 |
|
|
ASN1_check_infinite_end(unsigned char **p, long len) |
85 |
|
|
{ |
86 |
|
|
return _asn1_check_infinite_end((const unsigned char **)p, len); |
87 |
|
|
} |
88 |
|
|
|
89 |
|
|
int |
90 |
|
|
ASN1_const_check_infinite_end(const unsigned char **p, long len) |
91 |
|
|
{ |
92 |
|
|
return _asn1_check_infinite_end(p, len); |
93 |
|
|
} |
94 |
|
|
|
95 |
|
|
int |
96 |
|
|
ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, |
97 |
|
|
int *pclass, long omax) |
98 |
|
|
{ |
99 |
|
|
int i, ret; |
100 |
|
|
long l; |
101 |
|
1775576 |
const unsigned char *p= *pp; |
102 |
|
887788 |
int tag, xclass, inf; |
103 |
|
|
long max = omax; |
104 |
|
|
|
105 |
✓✗ |
887788 |
if (!max) |
106 |
|
|
goto err; |
107 |
|
887788 |
ret = (*p & V_ASN1_CONSTRUCTED); |
108 |
|
887788 |
xclass = (*p & V_ASN1_PRIVATE); |
109 |
|
887788 |
i= *p & V_ASN1_PRIMITIVE_TAG; |
110 |
✗✓ |
887788 |
if (i == V_ASN1_PRIMITIVE_TAG) { /* high-tag */ |
111 |
|
|
p++; |
112 |
|
|
if (--max == 0) |
113 |
|
|
goto err; |
114 |
|
|
l = 0; |
115 |
|
|
while (*p & 0x80) { |
116 |
|
|
l <<= 7L; |
117 |
|
|
l |= *(p++) & 0x7f; |
118 |
|
|
if (--max == 0) |
119 |
|
|
goto err; |
120 |
|
|
if (l > (INT_MAX >> 7L)) |
121 |
|
|
goto err; |
122 |
|
|
} |
123 |
|
|
l <<= 7L; |
124 |
|
|
l |= *(p++) & 0x7f; |
125 |
|
|
tag = (int)l; |
126 |
|
|
if (--max == 0) |
127 |
|
|
goto err; |
128 |
|
|
} else { |
129 |
|
|
tag = i; |
130 |
|
887788 |
p++; |
131 |
✓✗ |
887788 |
if (--max == 0) |
132 |
|
|
goto err; |
133 |
|
|
} |
134 |
|
887788 |
*ptag = tag; |
135 |
|
887788 |
*pclass = xclass; |
136 |
✓✗ |
887788 |
if (!asn1_get_length(&p, &inf, plength, (int)max)) |
137 |
|
|
goto err; |
138 |
|
|
|
139 |
✗✓✗✗
|
887788 |
if (inf && !(ret & V_ASN1_CONSTRUCTED)) |
140 |
|
|
goto err; |
141 |
|
|
|
142 |
✓✓ |
887788 |
if (*plength > (omax - (p - *pp))) { |
143 |
|
248 |
ASN1error(ASN1_R_TOO_LONG); |
144 |
|
|
/* Set this so that even if things are not long enough |
145 |
|
|
* the values are set correctly */ |
146 |
|
248 |
ret |= 0x80; |
147 |
|
248 |
} |
148 |
|
887788 |
*pp = p; |
149 |
|
887788 |
return (ret | inf); |
150 |
|
|
|
151 |
|
|
err: |
152 |
|
|
ASN1error(ASN1_R_HEADER_TOO_LONG); |
153 |
|
|
return (0x80); |
154 |
|
887788 |
} |
155 |
|
|
|
156 |
|
|
static int |
157 |
|
|
asn1_get_length(const unsigned char **pp, int *inf, long *rl, int max) |
158 |
|
|
{ |
159 |
|
1775576 |
const unsigned char *p= *pp; |
160 |
|
|
unsigned long ret = 0; |
161 |
|
|
unsigned int i; |
162 |
|
|
|
163 |
✗✓ |
887788 |
if (max-- < 1) |
164 |
|
|
return (0); |
165 |
✗✓ |
887788 |
if (*p == 0x80) { |
166 |
|
|
*inf = 1; |
167 |
|
|
ret = 0; |
168 |
|
|
p++; |
169 |
|
|
} else { |
170 |
|
887788 |
*inf = 0; |
171 |
|
887788 |
i= *p & 0x7f; |
172 |
✓✓ |
887788 |
if (*(p++) & 0x80) { |
173 |
✗✓ |
89489 |
if (max < (int)i) |
174 |
|
|
return (0); |
175 |
|
|
/* skip leading zeroes */ |
176 |
✓✗✗✓
|
268467 |
while (i && *p == 0) { |
177 |
|
|
p++; |
178 |
|
|
i--; |
179 |
|
|
} |
180 |
✗✓ |
89489 |
if (i > sizeof(long)) |
181 |
|
|
return 0; |
182 |
✓✓ |
500318 |
while (i-- > 0) { |
183 |
|
160670 |
ret <<= 8L; |
184 |
|
160670 |
ret |= *(p++); |
185 |
|
|
} |
186 |
|
|
} else |
187 |
|
798299 |
ret = i; |
188 |
|
|
} |
189 |
✗✓ |
887788 |
if (ret > LONG_MAX) |
190 |
|
|
return 0; |
191 |
|
887788 |
*pp = p; |
192 |
|
887788 |
*rl = (long)ret; |
193 |
|
887788 |
return (1); |
194 |
|
887788 |
} |
195 |
|
|
|
196 |
|
|
/* class 0 is constructed |
197 |
|
|
* constructed == 2 for indefinite length constructed */ |
198 |
|
|
void |
199 |
|
|
ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, |
200 |
|
|
int xclass) |
201 |
|
|
{ |
202 |
|
910632 |
unsigned char *p= *pp; |
203 |
|
|
int i, ttag; |
204 |
|
|
|
205 |
|
455316 |
i = (constructed) ? V_ASN1_CONSTRUCTED : 0; |
206 |
|
455316 |
i |= (xclass & V_ASN1_PRIVATE); |
207 |
✓✗ |
455316 |
if (tag < 31) |
208 |
|
455316 |
*(p++) = i | (tag & V_ASN1_PRIMITIVE_TAG); |
209 |
|
|
else { |
210 |
|
|
*(p++) = i | V_ASN1_PRIMITIVE_TAG; |
211 |
|
|
for(i = 0, ttag = tag; ttag > 0; i++) |
212 |
|
|
ttag >>= 7; |
213 |
|
|
ttag = i; |
214 |
|
|
while (i-- > 0) { |
215 |
|
|
p[i] = tag & 0x7f; |
216 |
|
|
if (i != (ttag - 1)) |
217 |
|
|
p[i] |= 0x80; |
218 |
|
|
tag >>= 7; |
219 |
|
|
} |
220 |
|
|
p += ttag; |
221 |
|
|
} |
222 |
✗✓ |
455316 |
if (constructed == 2) |
223 |
|
|
*(p++) = 0x80; |
224 |
|
|
else |
225 |
|
455316 |
asn1_put_length(&p, length); |
226 |
|
455316 |
*pp = p; |
227 |
|
455316 |
} |
228 |
|
|
|
229 |
|
|
int |
230 |
|
|
ASN1_put_eoc(unsigned char **pp) |
231 |
|
|
{ |
232 |
|
|
unsigned char *p = *pp; |
233 |
|
|
|
234 |
|
|
*p++ = 0; |
235 |
|
|
*p++ = 0; |
236 |
|
|
*pp = p; |
237 |
|
|
return 2; |
238 |
|
|
} |
239 |
|
|
|
240 |
|
|
static void |
241 |
|
|
asn1_put_length(unsigned char **pp, int length) |
242 |
|
|
{ |
243 |
|
910632 |
unsigned char *p= *pp; |
244 |
|
|
|
245 |
|
|
int i, l; |
246 |
✓✓ |
455316 |
if (length <= 127) |
247 |
|
444263 |
*(p++) = (unsigned char)length; |
248 |
|
|
else { |
249 |
|
|
l = length; |
250 |
✓✓ |
61162 |
for (i = 0; l > 0; i++) |
251 |
|
19528 |
l >>= 8; |
252 |
|
11053 |
*(p++) = i | 0x80; |
253 |
|
|
l = i; |
254 |
✓✓ |
61162 |
while (i-- > 0) { |
255 |
|
19528 |
p[i] = length & 0xff; |
256 |
|
19528 |
length >>= 8; |
257 |
|
|
} |
258 |
|
11053 |
p += l; |
259 |
|
|
} |
260 |
|
455316 |
*pp = p; |
261 |
|
455316 |
} |
262 |
|
|
|
263 |
|
|
int |
264 |
|
|
ASN1_object_size(int constructed, int length, int tag) |
265 |
|
|
{ |
266 |
|
|
int ret; |
267 |
|
|
|
268 |
|
|
ret = length; |
269 |
|
2978482 |
ret++; |
270 |
✗✓ |
1489241 |
if (tag >= 31) { |
271 |
|
|
while (tag > 0) { |
272 |
|
|
tag >>= 7; |
273 |
|
|
ret++; |
274 |
|
|
} |
275 |
|
|
} |
276 |
✗✓ |
1489241 |
if (constructed == 2) |
277 |
|
|
return ret + 3; |
278 |
|
1489241 |
ret++; |
279 |
✓✓ |
1489241 |
if (length > 127) { |
280 |
✓✓ |
160952 |
while (length > 0) { |
281 |
|
51222 |
length >>= 8; |
282 |
|
51222 |
ret++; |
283 |
|
|
} |
284 |
|
|
} |
285 |
|
1489241 |
return (ret); |
286 |
|
1489241 |
} |
287 |
|
|
|
288 |
|
|
static int |
289 |
|
|
_asn1_Finish(ASN1_const_CTX *c) |
290 |
|
|
{ |
291 |
|
|
if ((c->inf == (1|V_ASN1_CONSTRUCTED)) && (!c->eos)) { |
292 |
|
|
if (!ASN1_const_check_infinite_end(&c->p, c->slen)) { |
293 |
|
|
c->error = ERR_R_MISSING_ASN1_EOS; |
294 |
|
|
return (0); |
295 |
|
|
} |
296 |
|
|
} |
297 |
|
|
if (((c->slen != 0) && !(c->inf & 1)) || |
298 |
|
|
((c->slen < 0) && (c->inf & 1))) { |
299 |
|
|
c->error = ERR_R_ASN1_LENGTH_MISMATCH; |
300 |
|
|
return (0); |
301 |
|
|
} |
302 |
|
|
return (1); |
303 |
|
|
} |
304 |
|
|
|
305 |
|
|
int |
306 |
|
|
asn1_Finish(ASN1_CTX *c) |
307 |
|
|
{ |
308 |
|
|
return _asn1_Finish((ASN1_const_CTX *)c); |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
int |
312 |
|
|
asn1_const_Finish(ASN1_const_CTX *c) |
313 |
|
|
{ |
314 |
|
|
return _asn1_Finish(c); |
315 |
|
|
} |
316 |
|
|
|
317 |
|
|
int |
318 |
|
|
asn1_GetSequence(ASN1_const_CTX *c, long *length) |
319 |
|
|
{ |
320 |
|
|
const unsigned char *q; |
321 |
|
|
|
322 |
|
|
q = c->p; |
323 |
|
|
c->inf = ASN1_get_object(&(c->p), &(c->slen), &(c->tag), &(c->xclass), |
324 |
|
|
*length); |
325 |
|
|
if (c->inf & 0x80) { |
326 |
|
|
c->error = ERR_R_BAD_GET_ASN1_OBJECT_CALL; |
327 |
|
|
return (0); |
328 |
|
|
} |
329 |
|
|
if (c->tag != V_ASN1_SEQUENCE) { |
330 |
|
|
c->error = ERR_R_EXPECTING_AN_ASN1_SEQUENCE; |
331 |
|
|
return (0); |
332 |
|
|
} |
333 |
|
|
(*length) -= (c->p - q); |
334 |
|
|
if (c->max && (*length < 0)) { |
335 |
|
|
c->error = ERR_R_ASN1_LENGTH_MISMATCH; |
336 |
|
|
return (0); |
337 |
|
|
} |
338 |
|
|
if (c->inf == (1|V_ASN1_CONSTRUCTED)) |
339 |
|
|
c->slen= *length+ *(c->pp) - c->p; |
340 |
|
|
c->eos = 0; |
341 |
|
|
return (1); |
342 |
|
|
} |
343 |
|
|
|
344 |
|
|
int |
345 |
|
|
ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str) |
346 |
|
|
{ |
347 |
✗✓ |
138278 |
if (str == NULL) |
348 |
|
|
return 0; |
349 |
|
69139 |
dst->type = str->type; |
350 |
✗✓ |
69139 |
if (!ASN1_STRING_set(dst, str->data, str->length)) |
351 |
|
|
return 0; |
352 |
|
69139 |
dst->flags = str->flags; |
353 |
|
69139 |
return 1; |
354 |
|
69139 |
} |
355 |
|
|
|
356 |
|
|
ASN1_STRING * |
357 |
|
|
ASN1_STRING_dup(const ASN1_STRING *str) |
358 |
|
|
{ |
359 |
|
|
ASN1_STRING *ret; |
360 |
|
|
|
361 |
✗✓ |
138278 |
if (!str) |
362 |
|
|
return NULL; |
363 |
|
69139 |
ret = ASN1_STRING_new(); |
364 |
✗✓ |
69139 |
if (!ret) |
365 |
|
|
return NULL; |
366 |
✗✓ |
69139 |
if (!ASN1_STRING_copy(ret, str)) { |
367 |
|
|
ASN1_STRING_free(ret); |
368 |
|
|
return NULL; |
369 |
|
|
} |
370 |
|
69139 |
return ret; |
371 |
|
69139 |
} |
372 |
|
|
|
373 |
|
|
int |
374 |
|
|
ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len) |
375 |
|
|
{ |
376 |
|
|
const char *data = _data; |
377 |
|
|
|
378 |
✓✓ |
683592 |
if (len < 0) { |
379 |
✗✓ |
93 |
if (data == NULL) |
380 |
|
|
return (0); |
381 |
|
|
else |
382 |
|
93 |
len = strlen(data); |
383 |
|
93 |
} |
384 |
✓✓✗✓
|
341814 |
if ((str->length < len) || (str->data == NULL)) { |
385 |
|
|
unsigned char *tmp; |
386 |
|
341778 |
tmp = realloc(str->data, len + 1); |
387 |
✗✓ |
341778 |
if (tmp == NULL) { |
388 |
|
|
ASN1error(ERR_R_MALLOC_FAILURE); |
389 |
|
|
return (0); |
390 |
|
|
} |
391 |
|
341778 |
str->data = tmp; |
392 |
✓✗ |
341778 |
} |
393 |
|
341796 |
str->length = len; |
394 |
✓✓ |
341796 |
if (data != NULL) { |
395 |
|
341794 |
memmove(str->data, data, len); |
396 |
|
341794 |
} |
397 |
|
341796 |
str->data[str->length]='\0'; |
398 |
|
341796 |
return (1); |
399 |
|
341796 |
} |
400 |
|
|
|
401 |
|
|
void |
402 |
|
|
ASN1_STRING_set0(ASN1_STRING *str, void *data, int len) |
403 |
|
|
{ |
404 |
|
42 |
freezero(str->data, str->length); |
405 |
|
21 |
str->data = data; |
406 |
|
21 |
str->length = len; |
407 |
|
21 |
} |
408 |
|
|
|
409 |
|
|
ASN1_STRING * |
410 |
|
|
ASN1_STRING_new(void) |
411 |
|
|
{ |
412 |
|
138558 |
return (ASN1_STRING_type_new(V_ASN1_OCTET_STRING)); |
413 |
|
|
} |
414 |
|
|
|
415 |
|
|
ASN1_STRING * |
416 |
|
|
ASN1_STRING_type_new(int type) |
417 |
|
|
{ |
418 |
|
|
ASN1_STRING *ret; |
419 |
|
|
|
420 |
|
812588 |
ret = malloc(sizeof(ASN1_STRING)); |
421 |
✗✓ |
406294 |
if (ret == NULL) { |
422 |
|
|
ASN1error(ERR_R_MALLOC_FAILURE); |
423 |
|
|
return (NULL); |
424 |
|
|
} |
425 |
|
406294 |
ret->length = 0; |
426 |
|
406294 |
ret->type = type; |
427 |
|
406294 |
ret->data = NULL; |
428 |
|
406294 |
ret->flags = 0; |
429 |
|
406294 |
return (ret); |
430 |
|
406294 |
} |
431 |
|
|
|
432 |
|
|
void |
433 |
|
|
ASN1_STRING_free(ASN1_STRING *a) |
434 |
|
|
{ |
435 |
✓✗ |
811904 |
if (a == NULL) |
436 |
|
|
return; |
437 |
✓✓✓✗
|
811048 |
if (a->data != NULL && !(a->flags & ASN1_STRING_FLAG_NDEF)) |
438 |
|
405096 |
freezero(a->data, a->length); |
439 |
|
405952 |
free(a); |
440 |
|
811904 |
} |
441 |
|
|
|
442 |
|
|
int |
443 |
|
|
ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b) |
444 |
|
|
{ |
445 |
|
|
int i; |
446 |
|
|
|
447 |
|
950 |
i = (a->length - b->length); |
448 |
✓✓ |
475 |
if (i == 0) { |
449 |
|
473 |
i = memcmp(a->data, b->data, a->length); |
450 |
✓✗ |
473 |
if (i == 0) |
451 |
|
473 |
return (a->type - b->type); |
452 |
|
|
else |
453 |
|
|
return (i); |
454 |
|
|
} else |
455 |
|
2 |
return (i); |
456 |
|
475 |
} |
457 |
|
|
|
458 |
|
|
void |
459 |
|
|
asn1_add_error(const unsigned char *address, int offset) |
460 |
|
|
{ |
461 |
|
|
ERR_asprintf_error_data("offset=%d", offset); |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
int |
465 |
|
|
ASN1_STRING_length(const ASN1_STRING *x) |
466 |
|
|
{ |
467 |
|
954 |
return (x->length); |
468 |
|
|
} |
469 |
|
|
|
470 |
|
|
void |
471 |
|
|
ASN1_STRING_length_set(ASN1_STRING *x, int len) |
472 |
|
|
{ |
473 |
|
|
x->length = len; |
474 |
|
|
} |
475 |
|
|
|
476 |
|
|
int |
477 |
|
|
ASN1_STRING_type(ASN1_STRING *x) |
478 |
|
|
{ |
479 |
|
96 |
return (x->type); |
480 |
|
|
} |
481 |
|
|
|
482 |
|
|
unsigned char * |
483 |
|
|
ASN1_STRING_data(ASN1_STRING *x) |
484 |
|
|
{ |
485 |
|
950 |
return (x->data); |
486 |
|
|
} |