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