1 /* $OpenBSD: xdr.c,v 1.11 2010/09/01 14:43:34 millert 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 #ifndef lint 413 enum sizecheck { SIZEVAL }; /* used to find the size of an enum */ 414 415 /* 416 * enums are treated as ints 417 */ 418 if (sizeof (enum sizecheck) == sizeof (long)) { 419 return (xdr_long(xdrs, (long *)ep)); 420 } else if (sizeof (enum sizecheck) == sizeof (int)) { 421 return (xdr_int(xdrs, (int *)ep)); 422 } else if (sizeof (enum sizecheck) == sizeof (short)) { 423 return (xdr_short(xdrs, (short *)ep)); 424 } else { 425 return (FALSE); 426 } 427 #else 428 (void) (xdr_short(xdrs, (short *)ep)); 429 (void) (xdr_int(xdrs, (int *)ep)); 430 return (xdr_long(xdrs, (long *)ep)); 431 #endif 432 } 433 434 /* 435 * XDR opaque data 436 * Allows the specification of a fixed size sequence of opaque bytes. 437 * cp points to the opaque object and cnt gives the byte length. 438 */ 439 bool_t 440 xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt) 441 { 442 u_int rndup; 443 static int crud[BYTES_PER_XDR_UNIT]; 444 445 /* 446 * if no data we are done 447 */ 448 if (cnt == 0) 449 return (TRUE); 450 451 /* 452 * round byte count to full xdr units 453 */ 454 rndup = cnt % BYTES_PER_XDR_UNIT; 455 if (rndup > 0) 456 rndup = BYTES_PER_XDR_UNIT - rndup; 457 458 if (xdrs->x_op == XDR_DECODE) { 459 if (!XDR_GETBYTES(xdrs, cp, cnt)) { 460 return (FALSE); 461 } 462 if (rndup == 0) 463 return (TRUE); 464 return (XDR_GETBYTES(xdrs, (caddr_t)crud, rndup)); 465 } 466 467 if (xdrs->x_op == XDR_ENCODE) { 468 if (!XDR_PUTBYTES(xdrs, cp, cnt)) { 469 return (FALSE); 470 } 471 if (rndup == 0) 472 return (TRUE); 473 return (XDR_PUTBYTES(xdrs, xdr_zero, rndup)); 474 } 475 476 if (xdrs->x_op == XDR_FREE) { 477 return (TRUE); 478 } 479 480 return (FALSE); 481 } 482 483 /* 484 * XDR counted bytes 485 * *cpp is a pointer to the bytes, *sizep is the count. 486 * If *cpp is NULL maxsize bytes are allocated 487 */ 488 bool_t 489 xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize) 490 { 491 char *sp = *cpp; /* sp is the actual string pointer */ 492 u_int nodesize; 493 494 /* 495 * first deal with the length since xdr bytes are counted 496 */ 497 if (! xdr_u_int(xdrs, sizep)) { 498 return (FALSE); 499 } 500 nodesize = *sizep; 501 if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { 502 return (FALSE); 503 } 504 505 /* 506 * now deal with the actual bytes 507 */ 508 switch (xdrs->x_op) { 509 510 case XDR_DECODE: 511 if (nodesize == 0) { 512 return (TRUE); 513 } 514 if (sp == NULL) { 515 *cpp = sp = (char *)mem_alloc(nodesize); 516 } 517 if (sp == NULL) { 518 (void) fprintf(stderr, "xdr_bytes: out of memory\n"); 519 return (FALSE); 520 } 521 /* fall into ... */ 522 523 case XDR_ENCODE: 524 return (xdr_opaque(xdrs, sp, nodesize)); 525 526 case XDR_FREE: 527 if (sp != NULL) { 528 mem_free(sp, nodesize); 529 *cpp = NULL; 530 } 531 return (TRUE); 532 } 533 return (FALSE); 534 } 535 536 /* 537 * Implemented here due to commonality of the object. 538 */ 539 bool_t 540 xdr_netobj(XDR *xdrs, struct netobj *np) 541 { 542 543 return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ)); 544 } 545 546 /* 547 * XDR a descriminated union 548 * Support routine for discriminated unions. 549 * You create an array of xdrdiscrim structures, terminated with 550 * an entry with a null procedure pointer. The routine gets 551 * the discriminant value and then searches the array of xdrdiscrims 552 * looking for that value. It calls the procedure given in the xdrdiscrim 553 * to handle the discriminant. If there is no specific routine a default 554 * routine may be called. 555 * If there is no specific or default routine an error is returned. 556 */ 557 bool_t 558 xdr_union(XDR *xdrs, 559 int32_t *dscmp, /* enum to decide which arm to work on */ 560 char *unp, /* the union itself */ 561 struct xdr_discrim *choices, /* [value, xdr proc] for each arm */ 562 xdrproc_t dfault) /* default xdr routine */ 563 { 564 enum_t dscm; 565 566 /* 567 * we deal with the discriminator; it's an enum 568 */ 569 if (! xdr_enum(xdrs, dscmp)) { 570 return (FALSE); 571 } 572 dscm = *dscmp; 573 574 /* 575 * search choices for a value that matches the discriminator. 576 * if we find one, execute the xdr routine for that value. 577 */ 578 for (; choices->proc != NULL; choices++) { 579 if (choices->value == dscm) 580 return ((*(choices->proc))(xdrs, unp)); 581 } 582 583 /* 584 * no match - execute the default xdr routine if there is one 585 */ 586 return ((dfault == NULL) ? FALSE : 587 (*dfault)(xdrs, unp)); 588 } 589 590 591 /* 592 * Non-portable xdr primitives. 593 * Care should be taken when moving these routines to new architectures. 594 */ 595 596 597 /* 598 * XDR null terminated ASCII strings 599 * xdr_string deals with "C strings" - arrays of bytes that are 600 * terminated by a NULL character. The parameter cpp references a 601 * pointer to storage; If the pointer is null, then the necessary 602 * storage is allocated. The last parameter is the max allowed length 603 * of the string as specified by a protocol. 604 */ 605 bool_t 606 xdr_string(XDR *xdrs, char **cpp, u_int maxsize) 607 { 608 char *sp = *cpp; /* sp is the actual string pointer */ 609 u_int size; 610 u_int nodesize; 611 612 /* 613 * first deal with the length since xdr strings are counted-strings 614 */ 615 switch (xdrs->x_op) { 616 case XDR_FREE: 617 if (sp == NULL) { 618 return(TRUE); /* already free */ 619 } 620 /* fall through... */ 621 case XDR_ENCODE: 622 size = strlen(sp); 623 break; 624 } 625 if (! xdr_u_int(xdrs, &size)) { 626 return (FALSE); 627 } 628 if (size > maxsize) { 629 return (FALSE); 630 } 631 nodesize = size + 1; 632 633 /* 634 * now deal with the actual bytes 635 */ 636 switch (xdrs->x_op) { 637 638 case XDR_DECODE: 639 if (nodesize == 0) { 640 return (TRUE); 641 } 642 if (sp == NULL) 643 *cpp = sp = (char *)mem_alloc(nodesize); 644 if (sp == NULL) { 645 (void) fprintf(stderr, "xdr_string: out of memory\n"); 646 return (FALSE); 647 } 648 sp[size] = 0; 649 /* fall into ... */ 650 651 case XDR_ENCODE: 652 return (xdr_opaque(xdrs, sp, size)); 653 654 case XDR_FREE: 655 mem_free(sp, nodesize); 656 *cpp = NULL; 657 return (TRUE); 658 } 659 return (FALSE); 660 } 661 662 /* 663 * Wrapper for xdr_string that can be called directly from 664 * routines like clnt_call 665 */ 666 bool_t 667 xdr_wrapstring(XDR *xdrs, char **cpp) 668 { 669 return xdr_string(xdrs, cpp, LASTUNSIGNED); 670 } 671 672 bool_t 673 xdr_int64_t(XDR *xdrs, int64_t *llp) 674 { 675 u_long ul[2]; 676 677 switch (xdrs->x_op) { 678 case XDR_ENCODE: 679 ul[0] = (u_long)((u_int64_t)*llp >> 32) & 0xffffffff; 680 ul[1] = (u_long)((u_int64_t)*llp) & 0xffffffff; 681 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE) 682 return (FALSE); 683 return (XDR_PUTLONG(xdrs, (long *)&ul[1])); 684 case XDR_DECODE: 685 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE) 686 return (FALSE); 687 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE) 688 return (FALSE); 689 *llp = (int64_t) 690 (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); 691 return (TRUE); 692 case XDR_FREE: 693 return (TRUE); 694 } 695 /* NOTREACHED */ 696 return (FALSE); 697 } 698 699 bool_t 700 xdr_u_int64_t(XDR *xdrs, u_int64_t *ullp) 701 { 702 u_long ul[2]; 703 704 switch (xdrs->x_op) { 705 case XDR_ENCODE: 706 ul[0] = (u_long)(*ullp >> 32) & 0xffffffff; 707 ul[1] = (u_long)(*ullp) & 0xffffffff; 708 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE) 709 return (FALSE); 710 return (XDR_PUTLONG(xdrs, (long *)&ul[1])); 711 case XDR_DECODE: 712 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE) 713 return (FALSE); 714 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE) 715 return (FALSE); 716 *ullp = (u_int64_t) 717 (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); 718 return (TRUE); 719 case XDR_FREE: 720 return (TRUE); 721 } 722 /* NOTREACHED */ 723 return (FALSE); 724 } 725