1 /* $OpenBSD: xdr.c,v 1.12 2014/03/16 18:38:30 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2010, Oracle America, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * * Neither the name of the "Oracle America, Inc." nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * xdr.c, Generic XDR routines implementation. 36 * 37 * These are the "generic" xdr routines used to serialize and de-serialize 38 * most common data items. See xdr.h for more info on the interface to 39 * xdr. 40 */ 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 46 #include <rpc/types.h> 47 #include <rpc/xdr.h> 48 49 /* 50 * constants specific to the xdr "protocol" 51 */ 52 #define XDR_FALSE ((long) 0) 53 #define XDR_TRUE ((long) 1) 54 #define LASTUNSIGNED ((u_int) 0-1) 55 56 /* 57 * for unit alignment 58 */ 59 static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 }; 60 61 /* 62 * Free a data structure using XDR 63 * Not a filter, but a convenient utility nonetheless 64 */ 65 void 66 xdr_free(xdrproc_t proc, char *objp) 67 { 68 XDR x; 69 70 x.x_op = XDR_FREE; 71 (*proc)(&x, objp); 72 } 73 74 /* 75 * XDR nothing 76 */ 77 bool_t 78 xdr_void(void) 79 /* XDR *xdrs; */ 80 /* caddr_t addr; */ 81 { 82 83 return (TRUE); 84 } 85 86 87 /* 88 * XDR integers 89 */ 90 bool_t 91 xdr_int(XDR *xdrs, int *ip) 92 { 93 long l; 94 95 switch (xdrs->x_op) { 96 97 case XDR_ENCODE: 98 l = (long) *ip; 99 return (XDR_PUTLONG(xdrs, &l)); 100 101 case XDR_DECODE: 102 if (!XDR_GETLONG(xdrs, &l)) { 103 return (FALSE); 104 } 105 *ip = (int) l; 106 return (TRUE); 107 108 case XDR_FREE: 109 return (TRUE); 110 } 111 return (FALSE); 112 } 113 114 /* 115 * XDR unsigned integers 116 */ 117 bool_t 118 xdr_u_int(XDR *xdrs, u_int *up) 119 { 120 u_long l; 121 122 switch (xdrs->x_op) { 123 124 case XDR_ENCODE: 125 l = (u_long) *up; 126 return (XDR_PUTLONG(xdrs, (long *)&l)); 127 128 case XDR_DECODE: 129 if (!XDR_GETLONG(xdrs, (long *)&l)) { 130 return (FALSE); 131 } 132 *up = (u_int) l; 133 return (TRUE); 134 135 case XDR_FREE: 136 return (TRUE); 137 } 138 return (FALSE); 139 } 140 141 142 /* 143 * XDR long integers 144 * same as xdr_u_long - open coded to save a proc call! 145 */ 146 bool_t 147 xdr_long(XDR *xdrs, long int *lp) 148 { 149 switch (xdrs->x_op) { 150 case XDR_ENCODE: 151 return (XDR_PUTLONG(xdrs, lp)); 152 case XDR_DECODE: 153 return (XDR_GETLONG(xdrs, lp)); 154 case XDR_FREE: 155 return (TRUE); 156 } 157 158 return (FALSE); 159 } 160 161 /* 162 * XDR unsigned long integers 163 * same as xdr_long - open coded to save a proc call! 164 */ 165 bool_t 166 xdr_u_long(XDR *xdrs, u_long *ulp) 167 { 168 switch (xdrs->x_op) { 169 case XDR_ENCODE: 170 return (XDR_PUTLONG(xdrs, (long *)ulp)); 171 case XDR_DECODE: 172 return (XDR_GETLONG(xdrs, (long *)ulp)); 173 case XDR_FREE: 174 return (TRUE); 175 } 176 return (FALSE); 177 } 178 179 180 /* 181 * XDR 32-bit integers 182 * same as xdr_u_int32_t - open coded to save a proc call! 183 */ 184 bool_t 185 xdr_int32_t(XDR *xdrs, int32_t *int32_p) 186 { 187 long l; 188 189 switch (xdrs->x_op) { 190 191 case XDR_ENCODE: 192 l = (long) *int32_p; 193 return (XDR_PUTLONG(xdrs, &l)); 194 195 case XDR_DECODE: 196 if (!XDR_GETLONG(xdrs, &l)) { 197 return (FALSE); 198 } 199 *int32_p = (int32_t) l; 200 return (TRUE); 201 202 case XDR_FREE: 203 return (TRUE); 204 } 205 return (FALSE); 206 } 207 208 /* 209 * XDR unsigned 32-bit integers 210 * same as xdr_int32_t - open coded to save a proc call! 211 */ 212 bool_t 213 xdr_u_int32_t(XDR *xdrs, u_int32_t *u_int32_p) 214 { 215 u_long l; 216 217 switch (xdrs->x_op) { 218 219 case XDR_ENCODE: 220 l = (u_long) *u_int32_p; 221 return (XDR_PUTLONG(xdrs, (long *)&l)); 222 223 case XDR_DECODE: 224 if (!XDR_GETLONG(xdrs, (long *)&l)) { 225 return (FALSE); 226 } 227 *u_int32_p = (u_int32_t) l; 228 return (TRUE); 229 230 case XDR_FREE: 231 return (TRUE); 232 } 233 return (FALSE); 234 } 235 236 237 /* 238 * XDR short integers 239 */ 240 bool_t 241 xdr_short(XDR *xdrs, short int *sp) 242 { 243 long l; 244 245 switch (xdrs->x_op) { 246 247 case XDR_ENCODE: 248 l = (long) *sp; 249 return (XDR_PUTLONG(xdrs, &l)); 250 251 case XDR_DECODE: 252 if (!XDR_GETLONG(xdrs, &l)) { 253 return (FALSE); 254 } 255 *sp = (short) l; 256 return (TRUE); 257 258 case XDR_FREE: 259 return (TRUE); 260 } 261 return (FALSE); 262 } 263 264 /* 265 * XDR unsigned short integers 266 */ 267 bool_t 268 xdr_u_short(XDR *xdrs, u_short *usp) 269 { 270 u_long l; 271 272 switch (xdrs->x_op) { 273 274 case XDR_ENCODE: 275 l = (u_long) *usp; 276 return (XDR_PUTLONG(xdrs, (long *)&l)); 277 278 case XDR_DECODE: 279 if (!XDR_GETLONG(xdrs, (long *)&l)) { 280 return (FALSE); 281 } 282 *usp = (u_short) l; 283 return (TRUE); 284 285 case XDR_FREE: 286 return (TRUE); 287 } 288 return (FALSE); 289 } 290 291 292 /* 293 * XDR 16-bit integers 294 */ 295 bool_t 296 xdr_int16_t(XDR *xdrs, int16_t *int16_p) 297 { 298 long l; 299 300 switch (xdrs->x_op) { 301 302 case XDR_ENCODE: 303 l = (long) *int16_p; 304 return (XDR_PUTLONG(xdrs, &l)); 305 306 case XDR_DECODE: 307 if (!XDR_GETLONG(xdrs, &l)) { 308 return (FALSE); 309 } 310 *int16_p = (int16_t) l; 311 return (TRUE); 312 313 case XDR_FREE: 314 return (TRUE); 315 } 316 return (FALSE); 317 } 318 319 /* 320 * XDR unsigned 16-bit integers 321 */ 322 bool_t 323 xdr_u_int16_t(XDR *xdrs, u_int16_t *u_int16_p) 324 { 325 u_long l; 326 327 switch (xdrs->x_op) { 328 329 case XDR_ENCODE: 330 l = (u_long) *u_int16_p; 331 return (XDR_PUTLONG(xdrs, (long *)&l)); 332 333 case XDR_DECODE: 334 if (!XDR_GETLONG(xdrs, (long *)&l)) { 335 return (FALSE); 336 } 337 *u_int16_p = (u_int16_t) l; 338 return (TRUE); 339 340 case XDR_FREE: 341 return (TRUE); 342 } 343 return (FALSE); 344 } 345 346 347 /* 348 * XDR a char 349 */ 350 bool_t 351 xdr_char(XDR *xdrs, char *cp) 352 { 353 int i; 354 355 i = (*cp); 356 if (!xdr_int(xdrs, &i)) { 357 return (FALSE); 358 } 359 *cp = i; 360 return (TRUE); 361 } 362 363 /* 364 * XDR an unsigned char 365 */ 366 bool_t 367 xdr_u_char(XDR *xdrs, u_char *cp) 368 { 369 u_int u; 370 371 u = (*cp); 372 if (!xdr_u_int(xdrs, &u)) { 373 return (FALSE); 374 } 375 *cp = u; 376 return (TRUE); 377 } 378 379 /* 380 * XDR booleans 381 */ 382 bool_t 383 xdr_bool(XDR *xdrs, int32_t *bp) 384 { 385 long lb; 386 387 switch (xdrs->x_op) { 388 389 case XDR_ENCODE: 390 lb = *bp ? XDR_TRUE : XDR_FALSE; 391 return (XDR_PUTLONG(xdrs, &lb)); 392 393 case XDR_DECODE: 394 if (!XDR_GETLONG(xdrs, &lb)) { 395 return (FALSE); 396 } 397 *bp = (lb == XDR_FALSE) ? FALSE : TRUE; 398 return (TRUE); 399 400 case XDR_FREE: 401 return (TRUE); 402 } 403 return (FALSE); 404 } 405 406 /* 407 * XDR enumerations 408 */ 409 bool_t 410 xdr_enum(XDR *xdrs, int32_t *ep) 411 { 412 enum sizecheck { SIZEVAL }; /* used to find the size of an enum */ 413 414 /* 415 * enums are treated as ints 416 */ 417 if (sizeof (enum sizecheck) == sizeof (long)) { 418 return (xdr_long(xdrs, (long *)ep)); 419 } else if (sizeof (enum sizecheck) == sizeof (int)) { 420 return (xdr_int(xdrs, (int *)ep)); 421 } else if (sizeof (enum sizecheck) == sizeof (short)) { 422 return (xdr_short(xdrs, (short *)ep)); 423 } else { 424 return (FALSE); 425 } 426 } 427 428 /* 429 * XDR opaque data 430 * Allows the specification of a fixed size sequence of opaque bytes. 431 * cp points to the opaque object and cnt gives the byte length. 432 */ 433 bool_t 434 xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt) 435 { 436 u_int rndup; 437 static int crud[BYTES_PER_XDR_UNIT]; 438 439 /* 440 * if no data we are done 441 */ 442 if (cnt == 0) 443 return (TRUE); 444 445 /* 446 * round byte count to full xdr units 447 */ 448 rndup = cnt % BYTES_PER_XDR_UNIT; 449 if (rndup > 0) 450 rndup = BYTES_PER_XDR_UNIT - rndup; 451 452 if (xdrs->x_op == XDR_DECODE) { 453 if (!XDR_GETBYTES(xdrs, cp, cnt)) { 454 return (FALSE); 455 } 456 if (rndup == 0) 457 return (TRUE); 458 return (XDR_GETBYTES(xdrs, (caddr_t)crud, rndup)); 459 } 460 461 if (xdrs->x_op == XDR_ENCODE) { 462 if (!XDR_PUTBYTES(xdrs, cp, cnt)) { 463 return (FALSE); 464 } 465 if (rndup == 0) 466 return (TRUE); 467 return (XDR_PUTBYTES(xdrs, xdr_zero, rndup)); 468 } 469 470 if (xdrs->x_op == XDR_FREE) { 471 return (TRUE); 472 } 473 474 return (FALSE); 475 } 476 477 /* 478 * XDR counted bytes 479 * *cpp is a pointer to the bytes, *sizep is the count. 480 * If *cpp is NULL maxsize bytes are allocated 481 */ 482 bool_t 483 xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize) 484 { 485 char *sp = *cpp; /* sp is the actual string pointer */ 486 u_int nodesize; 487 488 /* 489 * first deal with the length since xdr bytes are counted 490 */ 491 if (! xdr_u_int(xdrs, sizep)) { 492 return (FALSE); 493 } 494 nodesize = *sizep; 495 if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { 496 return (FALSE); 497 } 498 499 /* 500 * now deal with the actual bytes 501 */ 502 switch (xdrs->x_op) { 503 504 case XDR_DECODE: 505 if (nodesize == 0) { 506 return (TRUE); 507 } 508 if (sp == NULL) { 509 *cpp = sp = (char *)mem_alloc(nodesize); 510 } 511 if (sp == NULL) { 512 (void) fprintf(stderr, "xdr_bytes: out of memory\n"); 513 return (FALSE); 514 } 515 /* fall into ... */ 516 517 case XDR_ENCODE: 518 return (xdr_opaque(xdrs, sp, nodesize)); 519 520 case XDR_FREE: 521 if (sp != NULL) { 522 mem_free(sp, nodesize); 523 *cpp = NULL; 524 } 525 return (TRUE); 526 } 527 return (FALSE); 528 } 529 530 /* 531 * Implemented here due to commonality of the object. 532 */ 533 bool_t 534 xdr_netobj(XDR *xdrs, struct netobj *np) 535 { 536 537 return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ)); 538 } 539 540 /* 541 * XDR a descriminated union 542 * Support routine for discriminated unions. 543 * You create an array of xdrdiscrim structures, terminated with 544 * an entry with a null procedure pointer. The routine gets 545 * the discriminant value and then searches the array of xdrdiscrims 546 * looking for that value. It calls the procedure given in the xdrdiscrim 547 * to handle the discriminant. If there is no specific routine a default 548 * routine may be called. 549 * If there is no specific or default routine an error is returned. 550 */ 551 bool_t 552 xdr_union(XDR *xdrs, 553 int32_t *dscmp, /* enum to decide which arm to work on */ 554 char *unp, /* the union itself */ 555 struct xdr_discrim *choices, /* [value, xdr proc] for each arm */ 556 xdrproc_t dfault) /* default xdr routine */ 557 { 558 enum_t dscm; 559 560 /* 561 * we deal with the discriminator; it's an enum 562 */ 563 if (! xdr_enum(xdrs, dscmp)) { 564 return (FALSE); 565 } 566 dscm = *dscmp; 567 568 /* 569 * search choices for a value that matches the discriminator. 570 * if we find one, execute the xdr routine for that value. 571 */ 572 for (; choices->proc != NULL; choices++) { 573 if (choices->value == dscm) 574 return ((*(choices->proc))(xdrs, unp)); 575 } 576 577 /* 578 * no match - execute the default xdr routine if there is one 579 */ 580 return ((dfault == NULL) ? FALSE : 581 (*dfault)(xdrs, unp)); 582 } 583 584 585 /* 586 * Non-portable xdr primitives. 587 * Care should be taken when moving these routines to new architectures. 588 */ 589 590 591 /* 592 * XDR null terminated ASCII strings 593 * xdr_string deals with "C strings" - arrays of bytes that are 594 * terminated by a NULL character. The parameter cpp references a 595 * pointer to storage; If the pointer is null, then the necessary 596 * storage is allocated. The last parameter is the max allowed length 597 * of the string as specified by a protocol. 598 */ 599 bool_t 600 xdr_string(XDR *xdrs, char **cpp, u_int maxsize) 601 { 602 char *sp = *cpp; /* sp is the actual string pointer */ 603 u_int size; 604 u_int nodesize; 605 606 /* 607 * first deal with the length since xdr strings are counted-strings 608 */ 609 switch (xdrs->x_op) { 610 case XDR_FREE: 611 if (sp == NULL) { 612 return(TRUE); /* already free */ 613 } 614 /* fall through... */ 615 case XDR_ENCODE: 616 size = strlen(sp); 617 break; 618 } 619 if (! xdr_u_int(xdrs, &size)) { 620 return (FALSE); 621 } 622 if (size > maxsize) { 623 return (FALSE); 624 } 625 nodesize = size + 1; 626 627 /* 628 * now deal with the actual bytes 629 */ 630 switch (xdrs->x_op) { 631 632 case XDR_DECODE: 633 if (nodesize == 0) { 634 return (TRUE); 635 } 636 if (sp == NULL) 637 *cpp = sp = (char *)mem_alloc(nodesize); 638 if (sp == NULL) { 639 (void) fprintf(stderr, "xdr_string: out of memory\n"); 640 return (FALSE); 641 } 642 sp[size] = 0; 643 /* fall into ... */ 644 645 case XDR_ENCODE: 646 return (xdr_opaque(xdrs, sp, size)); 647 648 case XDR_FREE: 649 mem_free(sp, nodesize); 650 *cpp = NULL; 651 return (TRUE); 652 } 653 return (FALSE); 654 } 655 656 /* 657 * Wrapper for xdr_string that can be called directly from 658 * routines like clnt_call 659 */ 660 bool_t 661 xdr_wrapstring(XDR *xdrs, char **cpp) 662 { 663 return xdr_string(xdrs, cpp, LASTUNSIGNED); 664 } 665 666 bool_t 667 xdr_int64_t(XDR *xdrs, int64_t *llp) 668 { 669 u_long ul[2]; 670 671 switch (xdrs->x_op) { 672 case XDR_ENCODE: 673 ul[0] = (u_long)((u_int64_t)*llp >> 32) & 0xffffffff; 674 ul[1] = (u_long)((u_int64_t)*llp) & 0xffffffff; 675 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE) 676 return (FALSE); 677 return (XDR_PUTLONG(xdrs, (long *)&ul[1])); 678 case XDR_DECODE: 679 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE) 680 return (FALSE); 681 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE) 682 return (FALSE); 683 *llp = (int64_t) 684 (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); 685 return (TRUE); 686 case XDR_FREE: 687 return (TRUE); 688 } 689 /* NOTREACHED */ 690 return (FALSE); 691 } 692 693 bool_t 694 xdr_u_int64_t(XDR *xdrs, u_int64_t *ullp) 695 { 696 u_long ul[2]; 697 698 switch (xdrs->x_op) { 699 case XDR_ENCODE: 700 ul[0] = (u_long)(*ullp >> 32) & 0xffffffff; 701 ul[1] = (u_long)(*ullp) & 0xffffffff; 702 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE) 703 return (FALSE); 704 return (XDR_PUTLONG(xdrs, (long *)&ul[1])); 705 case XDR_DECODE: 706 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE) 707 return (FALSE); 708 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE) 709 return (FALSE); 710 *ullp = (u_int64_t) 711 (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); 712 return (TRUE); 713 case XDR_FREE: 714 return (TRUE); 715 } 716 /* NOTREACHED */ 717 return (FALSE); 718 } 719