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