1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 /*
8  * lib/krb5/krb/serialize.c
9  *
10  * Copyright 1995 by the Massachusetts Institute of Technology.
11  * All Rights Reserved.
12  *
13  * Export of this software from the United States of America may
14  *   require a specific license from the United States Government.
15  *   It is the responsibility of any person or organization contemplating
16  *   export to obtain such a license before exporting.
17  *
18  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19  * distribute this software and its documentation for any purpose and
20  * without fee is hereby granted, provided that the above copyright
21  * notice appear in all copies and that both that copyright notice and
22  * this permission notice appear in supporting documentation, and that
23  * the name of M.I.T. not be used in advertising or publicity pertaining
24  * to distribution of the software without specific, written prior
25  * permission.  Furthermore if you modify this software you must label
26  * your software as modified software and not distribute it in such a
27  * fashion that it might be confused with the original M.I.T. software.
28  * M.I.T. makes no representations about the suitability of
29  * this software for any purpose.  It is provided "as is" without express
30  * or implied warranty.
31  *
32  */
33 
34 /*
35  * Base routines to deal with serialization of Kerberos metadata.
36  */
37 #include <k5-int.h>
38 
39 #include <k5-platform.h>
40 /*
41  * krb5_find_serializer()	- See if a particular type is registered.
42  */
43 krb5_ser_handle
44 krb5_find_serializer(krb5_context kcontext, krb5_magic odtype)
45 {
46     krb5_ser_handle	res;
47     krb5_ser_handle	sctx;
48     int			i;
49 
50     res = (krb5_ser_handle) NULL;
51     sctx = (krb5_ser_handle) kcontext->ser_ctx;
52     for (i=0; i<kcontext->ser_ctx_count; i++) {
53 	if (sctx[i].odtype == odtype) {
54 	    res = &sctx[i];
55 	    break;
56 	}
57     }
58     return(res);
59 }
60 
61 /*
62  * krb5_register_serializer()	- Register a particular serializer.
63  */
64 krb5_error_code
65 krb5_register_serializer(krb5_context kcontext, const krb5_ser_entry *entry)
66 {
67     krb5_error_code	kret;
68     krb5_ser_handle	stable;
69 
70     kret = 0;
71     /* See if it's already there, if so, we're good to go. */
72     if (!(stable = krb5_find_serializer(kcontext, entry->odtype))) {
73 	/*
74 	 * Can't find our type.  Create a new entry.
75 	 */
76 	if ((stable = (krb5_ser_handle) MALLOC(sizeof(krb5_ser_entry) *
77 					       (kcontext->ser_ctx_count+1)))) {
78 	    /* Copy in old table */
79 	    if (kcontext->ser_ctx_count)
80 		    (void) memcpy(stable, kcontext->ser_ctx,
81 			   sizeof(krb5_ser_entry) * kcontext->ser_ctx_count);
82 	    /* Copy in new entry */
83 	    (void) memcpy(&stable[kcontext->ser_ctx_count], entry,
84 		   sizeof(krb5_ser_entry));
85 	    if (kcontext->ser_ctx)
86 		krb5_xfree_wrap(kcontext->ser_ctx,
87 			sizeof(krb5_ser_entry) * (kcontext->ser_ctx_count));
88 	    kcontext->ser_ctx = (void *) stable;
89 	    kcontext->ser_ctx_count++;
90 	}
91 	else
92 	    kret = ENOMEM;
93     }
94     else
95 	(void) memcpy(stable, entry, sizeof(krb5_ser_entry));
96     return(kret);
97 }
98 
99 /*
100  * krb5_size_opaque()	- Determine the size necessary to serialize a given
101  *			  piece of opaque data.
102  */
103 krb5_error_code KRB5_CALLCONV
104 krb5_size_opaque(krb5_context kcontext, krb5_magic odtype, krb5_pointer arg, size_t *sizep)
105 {
106     krb5_error_code	kret;
107     krb5_ser_handle	shandle;
108 
109     kret = ENOENT;
110     /* See if the type is supported, if so, do it */
111     if ((shandle = krb5_find_serializer(kcontext, odtype)))
112 	kret = (shandle->sizer) ? (*shandle->sizer)(kcontext, arg, sizep) : 0;
113     return(kret);
114 }
115 
116 /*
117  * krb5_externalize_opaque()	- Externalize a piece of opaque data.
118  */
119 krb5_error_code KRB5_CALLCONV
120 krb5_externalize_opaque(krb5_context kcontext, krb5_magic odtype, krb5_pointer arg, krb5_octet **bufpp, size_t *sizep)
121 {
122     krb5_error_code	kret;
123     krb5_ser_handle	shandle;
124 
125     kret = ENOENT;
126     /* See if the type is supported, if so, do it */
127     if ((shandle = krb5_find_serializer(kcontext, odtype)))
128 	kret = (shandle->externalizer) ?
129 	    (*shandle->externalizer)(kcontext, arg, bufpp, sizep) : 0;
130     return(kret);
131 }
132 
133 /*
134  * Externalize a piece of arbitrary data.
135  */
136 krb5_error_code
137 krb5_externalize_data(krb5_context kcontext, krb5_pointer arg, krb5_octet **bufpp, size_t *sizep)
138 {
139     krb5_error_code	kret;
140     krb5_magic		*mp;
141     krb5_octet		*buffer, *bp;
142     size_t		bufsize, bsize;
143 
144     mp = (krb5_magic *) arg;
145     bufsize = 0;
146     if (!(kret = krb5_size_opaque(kcontext, *mp, arg, &bufsize))) {
147 	if ((buffer = (krb5_octet *) MALLOC(bufsize))) {
148 	    bp = buffer;
149 	    bsize = bufsize;
150 	    if (!(kret = krb5_externalize_opaque(kcontext,
151 						 *mp,
152 						 arg,
153 						 &bp,
154 						 &bsize))) {
155 		if (bsize != 0)
156 		    bufsize -= bsize;
157 		*bufpp = buffer;
158 		*sizep = bufsize;
159 	    }
160 	}
161 	else
162 	    kret = ENOMEM;
163     }
164     return(kret);
165 }
166 
167 /*
168  * krb5_internalize_opaque()	- Convert external representation into a data
169  *				  structure.
170  */
171 krb5_error_code KRB5_CALLCONV
172 krb5_internalize_opaque(krb5_context kcontext, krb5_magic odtype, krb5_pointer *argp, krb5_octet **bufpp, size_t *sizep)
173 {
174     krb5_error_code	kret;
175     krb5_ser_handle	shandle;
176 
177     kret = ENOENT;
178     /* See if the type is supported, if so, do it */
179     if ((shandle = krb5_find_serializer(kcontext, odtype)))
180 	kret = (shandle->internalizer) ?
181 	    (*shandle->internalizer)(kcontext, argp, bufpp, sizep) : 0;
182     return(kret);
183 }
184 
185 /*
186  * krb5_ser_pack_int32()	- Pack a 4-byte integer if space is availble.
187  *				  Update buffer pointer and remaining space.
188  */
189 krb5_error_code KRB5_CALLCONV
190 krb5_ser_pack_int32(krb5_int32 iarg, krb5_octet **bufp, size_t *remainp)
191 {
192     if (*remainp >= sizeof(krb5_int32)) {
193 	(*bufp)[0] = (krb5_octet) ((iarg >> 24) & 0xff);
194 	(*bufp)[1] = (krb5_octet) ((iarg >> 16) & 0xff);
195 	(*bufp)[2] = (krb5_octet) ((iarg >> 8) & 0xff);
196 	(*bufp)[3] = (krb5_octet) (iarg & 0xff);
197 	*bufp += sizeof(krb5_int32);
198 	*remainp -= sizeof(krb5_int32);
199 	return(0);
200     }
201     else
202 	return(ENOMEM);
203 }
204 
205 /*
206  * krb5_ser_pack_int64()	- Pack an 8-byte integer if space is available.
207  *				  Update buffer pointer and remaining space.
208  */
209 krb5_error_code KRB5_CALLCONV
210 krb5_ser_pack_int64(krb5_int64 iarg, krb5_octet **bufp, size_t *remainp)
211 {
212     if (*remainp >= sizeof(krb5_int64)) {
213 	store_64_be(iarg, (unsigned char *)*bufp);
214 	*bufp += sizeof(krb5_int64);
215 	*remainp -= sizeof(krb5_int64);
216 	return(0);
217     }
218     else
219         return(ENOMEM);
220 }
221 
222 /*
223  * krb5_ser_pack_bytes()	- Pack a string of bytes.
224  */
225 krb5_error_code KRB5_CALLCONV
226 krb5_ser_pack_bytes(krb5_octet *ostring, size_t osize, krb5_octet **bufp, size_t *remainp)
227 {
228     if (*remainp >= osize) {
229 	(void) memcpy(*bufp, ostring, osize);
230 	*bufp += osize;
231 	*remainp -= osize;
232 	return(0);
233     }
234     else
235 	return(ENOMEM);
236 }
237 
238 /*
239  * krb5_ser_unpack_int32()	- Unpack a 4-byte integer if it's there.
240  */
241 krb5_error_code KRB5_CALLCONV
242 krb5_ser_unpack_int32(krb5_int32 *intp, krb5_octet **bufp, size_t *remainp)
243 {
244     if (*remainp >= sizeof(krb5_int32)) {
245 	*intp = (((krb5_int32) ((unsigned char) (*bufp)[0]) << 24) |
246 		 ((krb5_int32) ((unsigned char) (*bufp)[1]) << 16) |
247 		 ((krb5_int32) ((unsigned char) (*bufp)[2]) << 8) |
248 		 ((krb5_int32) ((unsigned char) (*bufp)[3])));
249 	*bufp += sizeof(krb5_int32);
250 	*remainp -= sizeof(krb5_int32);
251 	return(0);
252     }
253     else
254 	return(ENOMEM);
255 }
256 
257 /*
258  * krb5_ser_unpack_int64()	- Unpack an 8-byte integer if it's there.
259  */
260 krb5_error_code KRB5_CALLCONV
261 krb5_ser_unpack_int64(krb5_int64 *intp, krb5_octet **bufp, size_t *remainp)
262 {
263     if (*remainp >= sizeof(krb5_int64)) {
264 	*intp = load_64_be((unsigned char *)*bufp);
265 	*bufp += sizeof(krb5_int64);
266 	*remainp -= sizeof(krb5_int64);
267 	return(0);
268     }
269     else
270         return(ENOMEM);
271 }
272 
273 /*
274  * krb5_ser_unpack_bytes()	- Unpack a byte string if it's there.
275  */
276 krb5_error_code KRB5_CALLCONV
277 krb5_ser_unpack_bytes(krb5_octet *istring, size_t isize, krb5_octet **bufp, size_t *remainp)
278 {
279     if (*remainp >= isize) {
280 	(void) memcpy(istring, *bufp, isize);
281 	*bufp += isize;
282 	*remainp -= isize;
283 	return(0);
284     }
285     else
286 	return(ENOMEM);
287 }
288