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