xref: /freebsd/crypto/krb5/src/util/support/ipc_stream.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* util/support/ipc_stream.c */
3 /*
4  * Copyright 2006, 2007, 2009 Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  * require a specific license from the United States Government.
9  * It is the responsibility of any person or organization contemplating
10  * export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26 
27 #ifdef _WIN32
28 #include <winsock2.h>
29 #endif
30 #include "k5-ipc_stream.h"
31 
32 #if !defined(htonll)
33 #define htonll(x) k5_htonll(x)
34 #endif
35 
36 #if !defined(ntohll)
37 #define ntohll(x) k5_ntohll(x)
38 #endif
39 
40 /* Add debugging later */
41 #define k5_check_error(x) (x)
42 
43 struct k5_ipc_stream_s {
44     char *data;
45     uint64_t size;
46     uint64_t max_size;
47 };
48 
49 static const struct k5_ipc_stream_s k5_ipc_stream_initializer = { NULL, 0, 0 };
50 
51 #define K5_IPC_STREAM_SIZE_INCREMENT 128
52 
53 /* ------------------------------------------------------------------------ */
54 
krb5int_ipc_stream_reallocate(k5_ipc_stream io_stream,uint64_t in_new_size)55 static uint32_t krb5int_ipc_stream_reallocate (k5_ipc_stream io_stream,
56                                                uint64_t      in_new_size)
57 {
58     int32_t err = 0;
59     uint64_t new_max_size = 0;
60 
61     if (!io_stream) { err = k5_check_error (EINVAL); }
62 
63     if (!err) {
64         uint64_t old_max_size = io_stream->max_size;
65         new_max_size = io_stream->max_size;
66 
67         if (in_new_size > old_max_size) {
68             /* Expand the stream */
69             while (in_new_size > new_max_size) {
70                 new_max_size += K5_IPC_STREAM_SIZE_INCREMENT;
71             }
72 
73 
74         } else if ((in_new_size + K5_IPC_STREAM_SIZE_INCREMENT) < old_max_size) {
75             /* Shrink the array, but never drop below K5_IPC_STREAM_SIZE_INCREMENT */
76             while ((in_new_size + K5_IPC_STREAM_SIZE_INCREMENT) < new_max_size &&
77                    (new_max_size > K5_IPC_STREAM_SIZE_INCREMENT)) {
78                 new_max_size -= K5_IPC_STREAM_SIZE_INCREMENT;
79             }
80         }
81     }
82 
83     if (!err && new_max_size != io_stream->max_size) {
84         char *data = io_stream->data;
85 
86         if (!data) {
87             data = malloc (new_max_size * sizeof (*data));
88         } else {
89             data = realloc (data, new_max_size * sizeof (*data));
90         }
91 
92         if (data) {
93             io_stream->data = data;
94             io_stream->max_size = new_max_size;
95         } else {
96             err = k5_check_error (ENOMEM);
97         }
98     }
99 
100     return k5_check_error (err);
101 }
102 
103 /* ------------------------------------------------------------------------ */
104 
krb5int_ipc_stream_new(k5_ipc_stream * out_stream)105 int32_t krb5int_ipc_stream_new (k5_ipc_stream *out_stream)
106 {
107     int32_t err = 0;
108     k5_ipc_stream stream = NULL;
109 
110     if (!out_stream) { err = k5_check_error (EINVAL); }
111 
112     if (!err) {
113         stream = malloc (sizeof (*stream));
114         if (stream) {
115             *stream = k5_ipc_stream_initializer;
116         } else {
117             err = k5_check_error (ENOMEM);
118         }
119     }
120 
121     if (!err) {
122         *out_stream = stream;
123         stream = NULL;
124     }
125 
126     krb5int_ipc_stream_release (stream);
127 
128     return k5_check_error (err);
129 }
130 
131 
132 /* ------------------------------------------------------------------------ */
133 
krb5int_ipc_stream_release(k5_ipc_stream io_stream)134 uint32_t krb5int_ipc_stream_release (k5_ipc_stream io_stream)
135 {
136     int32_t err = 0;
137 
138     if (!err && io_stream) {
139         free (io_stream->data);
140         free (io_stream);
141     }
142 
143     return err;
144 }
145 
146 /* ------------------------------------------------------------------------ */
147 
krb5int_ipc_stream_size(k5_ipc_stream in_stream)148 uint64_t krb5int_ipc_stream_size (k5_ipc_stream in_stream)
149 {
150     return in_stream ? in_stream->size : 0;
151 }
152 
153 
154 /* ------------------------------------------------------------------------ */
155 
krb5int_ipc_stream_data(k5_ipc_stream in_stream)156 const char *krb5int_ipc_stream_data (k5_ipc_stream in_stream)
157 {
158     return in_stream ? in_stream->data : NULL;
159 }
160 
161 #ifdef TARGET_OS_MAC
162 #pragma mark -
163 #endif
164 
165 /* ------------------------------------------------------------------------ */
166 
krb5int_ipc_stream_read(k5_ipc_stream io_stream,void * io_data,uint64_t in_size)167 uint32_t krb5int_ipc_stream_read (k5_ipc_stream  io_stream,
168                                   void         *io_data,
169                                   uint64_t     in_size)
170 {
171     int32_t err = 0;
172 
173     if (!io_stream) { err = k5_check_error (EINVAL); }
174     if (!io_data  ) { err = k5_check_error (EINVAL); }
175 
176     if (!err) {
177         if (in_size > io_stream->size) {
178             err = k5_check_error (EINVAL);
179         }
180     }
181 
182     if (!err) {
183         memcpy (io_data, io_stream->data, in_size);
184         memmove (io_stream->data, &io_stream->data[in_size],
185                  io_stream->size - in_size);
186 
187         err = krb5int_ipc_stream_reallocate (io_stream, io_stream->size - in_size);
188 
189         if (!err) {
190             io_stream->size -= in_size;
191         }
192     }
193 
194     return k5_check_error (err);
195 }
196 
197 /* ------------------------------------------------------------------------ */
198 
krb5int_ipc_stream_write(k5_ipc_stream io_stream,const void * in_data,uint64_t in_size)199 uint32_t krb5int_ipc_stream_write (k5_ipc_stream  io_stream,
200                                    const void   *in_data,
201                                    uint64_t     in_size)
202 {
203     int32_t err = 0;
204 
205     if (!io_stream) { err = k5_check_error (EINVAL); }
206     if (!in_data  ) { err = k5_check_error (EINVAL); }
207 
208     if (!err) {
209         /* Security check: Do not let the caller overflow the length */
210         if (in_size > (UINT64_MAX - io_stream->size)) {
211             err = k5_check_error (EINVAL);
212         }
213     }
214 
215     if (!err) {
216         err = krb5int_ipc_stream_reallocate (io_stream, io_stream->size + in_size);
217     }
218 
219     if (!err) {
220         memcpy (&io_stream->data[io_stream->size], in_data, in_size);
221         io_stream->size += in_size;
222     }
223 
224     return k5_check_error (err);
225 }
226 
227 #ifdef TARGET_OS_MAC
228 #pragma mark -
229 #endif
230 
231 /* ------------------------------------------------------------------------ */
232 
krb5int_ipc_stream_free_string(char * in_string)233 void krb5int_ipc_stream_free_string (char *in_string)
234 {
235     free (in_string);
236 }
237 
238 /* ------------------------------------------------------------------------ */
239 
krb5int_ipc_stream_read_string(k5_ipc_stream io_stream,char ** out_string)240 uint32_t krb5int_ipc_stream_read_string (k5_ipc_stream   io_stream,
241                                          char         **out_string)
242 {
243     int32_t err = 0;
244     uint32_t length = 0;
245     char *string = NULL;
246 
247     if (!io_stream ) { err = k5_check_error (EINVAL); }
248     if (!out_string) { err = k5_check_error (EINVAL); }
249 
250     if (!err) {
251         err = krb5int_ipc_stream_read_uint32 (io_stream, &length);
252     }
253 
254     if (!err) {
255         string = malloc (length);
256         if (!string) { err = k5_check_error (ENOMEM); }
257     }
258 
259     if (!err) {
260         err = krb5int_ipc_stream_read (io_stream, string, length);
261     }
262 
263     if (!err) {
264         *out_string = string;
265         string = NULL;
266     }
267 
268     free (string);
269 
270     return k5_check_error (err);
271 }
272 
273 /* ------------------------------------------------------------------------ */
274 
krb5int_ipc_stream_write_string(k5_ipc_stream io_stream,const char * in_string)275 uint32_t krb5int_ipc_stream_write_string (k5_ipc_stream  io_stream,
276                                           const char    *in_string)
277 {
278     int32_t err = 0;
279     uint32_t length = 0;
280 
281     if (!io_stream) { err = k5_check_error (EINVAL); }
282     if (!in_string) { err = k5_check_error (EINVAL); }
283 
284     if (!err) {
285         length = strlen (in_string) + 1;
286 
287         err = krb5int_ipc_stream_write_uint32 (io_stream, length);
288     }
289 
290     if (!err) {
291         err = krb5int_ipc_stream_write (io_stream, in_string, length);
292     }
293 
294     return k5_check_error (err);
295 }
296 
297 #ifdef TARGET_OS_MAC
298 #pragma mark -
299 #endif
300 
301 /* ------------------------------------------------------------------------ */
302 
krb5int_ipc_stream_read_int32(k5_ipc_stream io_stream,int32_t * out_int32)303 uint32_t krb5int_ipc_stream_read_int32 (k5_ipc_stream  io_stream,
304                                         int32_t       *out_int32)
305 {
306     int32_t err = 0;
307     int32_t int32 = 0;
308 
309     if (!io_stream) { err = k5_check_error (EINVAL); }
310     if (!out_int32) { err = k5_check_error (EINVAL); }
311 
312     if (!err) {
313         err = krb5int_ipc_stream_read (io_stream, &int32, sizeof (int32));
314     }
315 
316     if (!err) {
317         *out_int32 = ntohl (int32);
318     }
319 
320     return k5_check_error (err);
321 }
322 
323 /* ------------------------------------------------------------------------ */
324 
krb5int_ipc_stream_write_int32(k5_ipc_stream io_stream,int32_t in_int32)325 uint32_t krb5int_ipc_stream_write_int32 (k5_ipc_stream io_stream,
326                                          int32_t       in_int32)
327 {
328     int32_t err = 0;
329     int32_t int32 = htonl (in_int32);
330 
331     if (!io_stream) { err = k5_check_error (EINVAL); }
332 
333     if (!err) {
334         err = krb5int_ipc_stream_write (io_stream, &int32, sizeof (int32));
335     }
336 
337     return k5_check_error (err);
338 }
339 
340 #ifdef TARGET_OS_MAC
341 #pragma mark -
342 #endif
343 
344 /* ------------------------------------------------------------------------ */
345 
krb5int_ipc_stream_read_uint32(k5_ipc_stream io_stream,uint32_t * out_uint32)346 uint32_t krb5int_ipc_stream_read_uint32 (k5_ipc_stream  io_stream,
347                                          uint32_t      *out_uint32)
348 {
349     int32_t err = 0;
350     uint32_t uint32 = 0;
351 
352     if (!io_stream) { err = k5_check_error (EINVAL); }
353     if (!out_uint32) { err = k5_check_error (EINVAL); }
354 
355     if (!err) {
356         err = krb5int_ipc_stream_read (io_stream, &uint32, sizeof (uint32));
357     }
358 
359     if (!err) {
360         *out_uint32 = ntohl (uint32);
361     }
362 
363     return k5_check_error (err);
364 }
365 
366 /* ------------------------------------------------------------------------ */
367 
krb5int_ipc_stream_write_uint32(k5_ipc_stream io_stream,uint32_t in_uint32)368 uint32_t krb5int_ipc_stream_write_uint32 (k5_ipc_stream io_stream,
369                                           uint32_t      in_uint32)
370 {
371     int32_t err = 0;
372     int32_t uint32 = htonl (in_uint32);
373 
374     if (!io_stream) { err = k5_check_error (EINVAL); }
375 
376     if (!err) {
377         err = krb5int_ipc_stream_write (io_stream, &uint32, sizeof (uint32));
378     }
379 
380     return k5_check_error (err);
381 }
382 
383 #ifdef TARGET_OS_MAC
384 #pragma mark -
385 #endif
386 
387 /* ------------------------------------------------------------------------ */
388 
krb5int_ipc_stream_read_int64(k5_ipc_stream io_stream,int64_t * out_int64)389 uint32_t krb5int_ipc_stream_read_int64 (k5_ipc_stream  io_stream,
390                                         int64_t       *out_int64)
391 {
392     int32_t err = 0;
393     uint64_t int64 = 0;
394 
395     if (!io_stream) { err = k5_check_error (EINVAL); }
396     if (!out_int64) { err = k5_check_error (EINVAL); }
397 
398     if (!err) {
399         err = krb5int_ipc_stream_read (io_stream, &int64, sizeof (int64));
400     }
401 
402     if (!err) {
403         *out_int64 = ntohll (int64);
404     }
405 
406     return k5_check_error (err);
407 }
408 
409 /* ------------------------------------------------------------------------ */
410 
krb5int_ipc_stream_write_int64(k5_ipc_stream io_stream,int64_t in_int64)411 uint32_t krb5int_ipc_stream_write_int64 (k5_ipc_stream io_stream,
412                                          int64_t     in_int64)
413 {
414     int32_t err = 0;
415     int64_t int64 = htonll (in_int64);
416 
417     if (!io_stream) { err = k5_check_error (EINVAL); }
418 
419     if (!err) {
420         err = krb5int_ipc_stream_write (io_stream, &int64, sizeof (int64));
421     }
422 
423     return k5_check_error (err);
424 }
425 
426 
427 #ifdef TARGET_OS_MAC
428 #pragma mark -
429 #endif
430 
431 /* ------------------------------------------------------------------------ */
432 
krb5int_ipc_stream_read_uint64(k5_ipc_stream io_stream,uint64_t * out_uint64)433 uint32_t krb5int_ipc_stream_read_uint64 (k5_ipc_stream  io_stream,
434                                          uint64_t     *out_uint64)
435 {
436     int32_t err = 0;
437     uint64_t uint64 = 0;
438 
439     if (!io_stream) { err = k5_check_error (EINVAL); }
440     if (!out_uint64) { err = k5_check_error (EINVAL); }
441 
442     if (!err) {
443         err = krb5int_ipc_stream_read (io_stream, &uint64, sizeof (uint64));
444     }
445 
446     if (!err) {
447         *out_uint64 = ntohll (uint64);
448     }
449 
450     return k5_check_error (err);
451 }
452 
453 /* ------------------------------------------------------------------------ */
454 
krb5int_ipc_stream_write_uint64(k5_ipc_stream io_stream,uint64_t in_uint64)455 uint32_t krb5int_ipc_stream_write_uint64 (k5_ipc_stream io_stream,
456                                           uint64_t      in_uint64)
457 {
458     int32_t err = 0;
459     int64_t uint64 = htonll (in_uint64);
460 
461     if (!io_stream) { err = k5_check_error (EINVAL); }
462 
463     if (!err) {
464         err = krb5int_ipc_stream_write (io_stream, &uint64, sizeof (uint64));
465     }
466 
467     return k5_check_error (err);
468 }
469