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