1 /*
2  * Copyright (C) 2003-2015 FreeIPMI Core Team
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif /* HAVE_CONFIG_H */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #ifdef STDC_HEADERS
26 #include <string.h>
27 #include <stdarg.h>
28 #endif /* STDC_HEADERS */
29 #include <limits.h>
30 #include <assert.h>
31 #include <errno.h>
32 
33 #include "freeipmi/fiid/fiid.h"
34 
35 #include "libcommon/ipmi-bit-ops.h"
36 
37 #include "freeipmi-portability.h"
38 #include "hash.h"
39 #include "secure.h"
40 
41 #define FIID_OBJ_MAGIC 0xf00fd00d
42 #define FIID_ITERATOR_MAGIC 0xd00df00f
43 
44 struct fiid_field_data
45 {
46   unsigned int max_field_len;
47   char key[FIID_FIELD_MAX_KEY_LEN + 1];
48   unsigned int set_field_len;
49   unsigned int flags;
50   unsigned int index;           /* for lookup */
51   unsigned int start;           /* for lookup */
52   unsigned int end;             /* for lookup */
53 };
54 
55 struct fiid_obj
56 {
57   uint32_t magic;
58   fiid_err_t errnum;
59   uint8_t *data;
60   unsigned int data_len;
61   struct fiid_field_data *field_data;
62   unsigned int field_data_len;
63   hash_t lookup;
64   int makes_packet_sufficient;  /* flag for internal use */
65   int secure_memset_on_clear;   /* flag for internal use */
66 };
67 
68 struct fiid_iterator
69 {
70   uint32_t magic;
71   fiid_err_t errnum;
72   unsigned int current_index;
73   unsigned int last_index;
74   struct fiid_obj *obj;
75 };
76 
77 static char * fiid_errmsg[] =
78   {
79     "success",
80     "fiid object null",
81     "fiid object invalid",
82     "fiid iterator null",
83     "fiid iterator invalid",
84     "invalid parameter",
85     "invalid template specified",
86     "field not found",
87     "template key invalid",
88     "template flags invalid",
89     "template not byte aligned",
90     "field not byte aligned",
91     "block not byte aligned",
92     "buffer too small to hold result",
93     "template max field length mismatch",
94     "template key mismatch",
95     "template flags mismatch",
96     "template length mismatch",
97     "data not byte aligned",
98     "required field missing",
99     "fixed length field invalid",
100     "data not available",
101     "not identical",
102     "out of memory",
103     "internal error",
104     "errnum out of range",
105   };
106 
107 #ifndef NDEBUG
108 static int
_fiid_template_check_valid_keys(fiid_template_t tmpl)109 _fiid_template_check_valid_keys (fiid_template_t tmpl)
110 {
111   unsigned int i;
112 
113   assert (tmpl);
114 
115   for (i = 0; tmpl[i].max_field_len; i++)
116     {
117       unsigned int len;
118 
119       len = strlen (tmpl[i].key);
120       if (!len || len > FIID_FIELD_MAX_KEY_LEN)
121         return (-1);
122     }
123 
124   return (0);
125 }
126 #endif /* NDEBUG */
127 
128 static int
_fiid_template_check_valid_flags(fiid_template_t tmpl)129 _fiid_template_check_valid_flags (fiid_template_t tmpl)
130 {
131   unsigned int i;
132 
133   assert (tmpl);
134 
135   for (i = 0; tmpl[i].max_field_len; i++)
136     {
137       if (!FIID_FIELD_REQUIRED_FLAG_VALID (tmpl[i].flags)
138           || !FIID_FIELD_LENGTH_FLAG_VALID (tmpl[i].flags))
139         return (-1);
140     }
141 
142   return (0);
143 }
144 
145 static int
_fiid_template_len(fiid_template_t tmpl,unsigned int * tmpl_field_count)146 _fiid_template_len (fiid_template_t tmpl,
147                     unsigned int *tmpl_field_count)
148 {
149   unsigned int i, len = 0;
150 
151   assert (tmpl);
152   assert (tmpl_field_count);
153 
154   for (i = 0; tmpl[i].max_field_len; i++)
155     {
156       if (tmpl[i].max_field_len > INT_MAX)
157         {
158           /* FIID_ERR_OVERFLOW */
159           errno = EINVAL;
160           return (-1);
161         }
162 
163       len += tmpl[i].max_field_len;
164 
165       /* check for integer overflow */
166       if (len < tmpl[i].max_field_len)
167         {
168           /* FIID_ERR_OVERFLOW */
169           errno = EINVAL;
170           return (-1);
171         }
172     }
173 
174   if (len > INT_MAX)
175     {
176       /* FIID_ERR_OVERFLOW */
177       errno = EINVAL;
178       return (-1);
179     }
180 
181   if (len % 8)
182     {
183       /* FIID_ERR_TEMPLATE_NOT_BYTE_ALIGNED */
184       errno = EINVAL;
185       return (-1);
186     }
187 
188   *tmpl_field_count = (i + 1);
189   return (len);
190 }
191 
192 static int
_fiid_template_len_bytes(fiid_template_t tmpl,unsigned int * tmpl_field_count)193 _fiid_template_len_bytes (fiid_template_t tmpl,
194                           unsigned int *tmpl_field_count)
195 {
196   int len;
197 
198   assert (tmpl);
199   assert (tmpl_field_count);
200 
201   if ((len = _fiid_template_len (tmpl,
202                                  tmpl_field_count)) < 0)
203     return (-1);
204 
205   return (BITS_ROUND_BYTES (len));
206 }
207 
208 int
fiid_template_field_lookup(fiid_template_t tmpl,const char * field)209 fiid_template_field_lookup (fiid_template_t tmpl,
210                             const char *field)
211 {
212   unsigned int i;
213 
214   if (!(tmpl && field))
215     {
216       /* FIID_ERR_PARAMETERS */
217       errno = EINVAL;
218       return (-1);
219     }
220 
221 #ifndef NDEBUG
222   if (_fiid_template_check_valid_keys (tmpl) < 0)
223     {
224       /* FIID_ERR_PARAMETERS */
225       errno = EINVAL;
226       return (-1);
227     }
228 #endif /* NDEBUG */
229 
230   for (i = 0; tmpl[i].max_field_len; i++)
231     {
232       if (!strcmp (tmpl[i].key, field))
233         return (1);
234     }
235 
236   return (0);
237 }
238 
239 int
FIID_TEMPLATE_FIELD_LOOKUP(fiid_template_t tmpl,const char * field)240 FIID_TEMPLATE_FIELD_LOOKUP (fiid_template_t tmpl,
241                             const char *field)
242 {
243   int ret;
244 
245   if ((ret = fiid_template_field_lookup (tmpl, field)) < 0)
246     return (ret);
247 
248   if (!ret)
249     {
250       errno = EINVAL;
251       return (-1);
252     }
253 
254   return (ret);
255 }
256 
257 int
fiid_template_len(fiid_template_t tmpl)258 fiid_template_len (fiid_template_t tmpl)
259 {
260   unsigned int temp;
261   int len = 0;
262 
263   if (!tmpl)
264     {
265       /* FIID_ERR_PARAMETERS */
266       errno = EINVAL;
267       return (-1);
268     }
269 
270   if ((len = _fiid_template_len (tmpl,
271                                  &temp)) < 0)
272     return (-1);
273 
274   return (len);
275 }
276 
277 int
fiid_template_len_bytes(fiid_template_t tmpl)278 fiid_template_len_bytes (fiid_template_t tmpl)
279 {
280   int len;
281 
282   if (!tmpl)
283     {
284       /* FIID_ERR_PARAMETERS */
285       errno = EINVAL;
286       return (-1);
287     }
288 
289   if ((len = fiid_template_len (tmpl)) < 0)
290     return (-1);
291 
292   if (len % 8)
293     {
294       /* FIID_ERR_TEMPLATE_NOT_BYTE_ALIGNED */
295       errno = EINVAL;
296       return (-1);
297     }
298 
299   return (BITS_ROUND_BYTES (len));
300 }
301 
302 static int
_fiid_template_field_start_end(fiid_template_t tmpl,const char * field,unsigned int * start,unsigned int * end)303 _fiid_template_field_start_end (fiid_template_t tmpl,
304                                 const char *field,
305                                 unsigned int *start,
306                                 unsigned int *end)
307 {
308   unsigned int i = 0;
309   unsigned int _start = 0;
310   unsigned int _end = 0;
311 
312   assert (tmpl);
313   assert (field);
314   assert (start);
315   assert (end);
316 
317   for (i = 0; tmpl[i].max_field_len; i++)
318     {
319       if (strcmp (tmpl[i].key, field) == 0)
320         {
321           if (tmpl[i].max_field_len > INT_MAX)
322             {
323               /* FIID_ERR_OVERFLOW */
324               errno = EINVAL;
325               return (-1);
326             }
327 
328           _end = _start + tmpl[i].max_field_len;
329 
330           /* check for integer overflow */
331           if (_end < tmpl[i].max_field_len)
332             {
333               /* FIID_ERR_OVERFLOW */
334               errno = EINVAL;
335               return (-1);
336             }
337 
338           *start = _start;
339           *end = _end;
340           return (tmpl[i].max_field_len);
341         }
342 
343       _start += tmpl[i].max_field_len;
344 
345       /* check for integer overflow */
346       if (_start < tmpl[i].max_field_len)
347         {
348           /* FIID_ERR_OVERFLOW */
349           errno = EINVAL;
350           return (-1);
351         }
352     }
353 
354   /* FIID_ERR_FIELD_NOT_FOUND */
355   errno = EINVAL;
356   return (-1);
357 }
358 
359 static int
_fiid_template_field_start(fiid_template_t tmpl,const char * field)360 _fiid_template_field_start (fiid_template_t tmpl,
361                             const char *field)
362 {
363   unsigned int start = 0;
364   unsigned int end = 0;
365 
366   assert (tmpl);
367   assert (field);
368 
369   if (_fiid_template_field_start_end (tmpl,
370                                       field,
371                                       &start,
372                                       &end) < 0)
373     return (-1);
374 
375   if (start > INT_MAX)
376     {
377       /* FIID_ERR_OVERFLOW */
378       errno = EINVAL;
379       return (-1);
380     }
381 
382   return (start);
383 }
384 
385 int
fiid_template_field_start(fiid_template_t tmpl,const char * field)386 fiid_template_field_start (fiid_template_t tmpl,
387                            const char *field)
388 {
389   if (!tmpl || !field)
390     {
391       /* FIID_ERR_PARAMETERS */
392       errno = EINVAL;
393       return (-1);
394     }
395 
396 #ifndef NDEBUG
397   if (_fiid_template_check_valid_keys (tmpl) < 0)
398     {
399       /* FIID_ERR_PARAMETERS */
400       errno = EINVAL;
401       return (-1);
402     }
403 #endif /* NDEBUG */
404 
405   return (_fiid_template_field_start (tmpl, field));
406 }
407 
408 int
fiid_template_field_start_bytes(fiid_template_t tmpl,const char * field)409 fiid_template_field_start_bytes (fiid_template_t tmpl,
410                                  const char *field)
411 {
412   int start = 0;
413 
414   if (!tmpl || !field)
415     {
416       /* FIID_ERR_PARAMETERS */
417       errno = EINVAL;
418       return (-1);
419     }
420 
421 #ifndef NDEBUG
422   if (_fiid_template_check_valid_keys (tmpl) < 0)
423     {
424       /* FIID_ERR_PARAMETERS */
425       errno = EINVAL;
426       return (-1);
427     }
428 #endif /* NDEBUG */
429 
430   if ((start = _fiid_template_field_start (tmpl,
431                                            field)) < 0)
432     return (-1);
433 
434   if (start % 8)
435     {
436       /* FIID_ERR_FIELD_NOT_BYTE_ALIGNED */
437       errno = EINVAL;
438       return (-1);
439     }
440 
441   return (BITS_ROUND_BYTES (start));
442 }
443 
444 static int
_fiid_template_field_end(fiid_template_t tmpl,const char * field)445 _fiid_template_field_end (fiid_template_t tmpl,
446                           const char *field)
447 {
448   unsigned int start = 0;
449   unsigned int end = 0;
450 
451   assert (tmpl);
452   assert (field);
453 
454   if (_fiid_template_field_start_end (tmpl,
455                                       field,
456                                       &start,
457                                       &end) < 0)
458     return (-1);
459 
460   if (end > INT_MAX)
461     {
462       /* FIID_ERR_OVERFLOW */
463       errno = EINVAL;
464       return (-1);
465     }
466 
467   return (end);
468 }
469 
470 int
fiid_template_field_end(fiid_template_t tmpl,const char * field)471 fiid_template_field_end (fiid_template_t tmpl,
472                          const char *field)
473 {
474   if (!tmpl || !field)
475     {
476       /* FIID_ERR_PARAMETERS */
477       errno = EINVAL;
478       return (-1);
479     }
480 
481 #ifndef NDEBUG
482   if (_fiid_template_check_valid_keys (tmpl) < 0)
483     {
484       /* FIID_ERR_PARAMETERS */
485       errno = EINVAL;
486       return (-1);
487     }
488 #endif /* NDEBUG */
489 
490   return (_fiid_template_field_end (tmpl, field));
491 }
492 
493 int
fiid_template_field_end_bytes(fiid_template_t tmpl,const char * field)494 fiid_template_field_end_bytes (fiid_template_t tmpl,
495                                const char *field)
496 {
497   int end = 0;
498 
499   if (!tmpl || !field)
500     {
501       /* FIID_ERR_PARAMETERS */
502       errno = EINVAL;
503       return (-1);
504     }
505 
506 #ifndef NDEBUG
507   if (_fiid_template_check_valid_keys (tmpl) < 0)
508     {
509       /* FIID_ERR_PARAMETERS */
510       errno = EINVAL;
511       return (-1);
512     }
513 #endif /* NDEBUG */
514 
515   if ((end = _fiid_template_field_end (tmpl,
516                                        field)) < 0)
517     return (-1);
518 
519   if (end % 8)
520     {
521       /* FIID_ERR_FIELD_NOT_BYTE_ALIGNED */
522       errno = EINVAL;
523       return (-1);
524     }
525 
526   return (BITS_ROUND_BYTES (end));
527 }
528 
529 static int
_fiid_template_field_len(fiid_template_t tmpl,const char * field)530 _fiid_template_field_len (fiid_template_t tmpl,
531                          const char *field)
532 {
533   unsigned int i;
534 
535   assert (tmpl);
536   assert (field);
537 
538   for (i = 0; tmpl[i].max_field_len; i++)
539     {
540       if (!strcmp (tmpl[i].key, field))
541         {
542           if (tmpl[i].max_field_len > INT_MAX)
543             {
544               /* FIID_ERR_OVERFLOW */
545               errno = EINVAL;
546               return (-1);
547             }
548 
549           return (tmpl[i].max_field_len);
550         }
551     }
552 
553   /* FIID_ERR_FIELD_NOT_FOUND */
554   errno = EINVAL;
555   return (-1);
556 }
557 
558 int
fiid_template_field_len(fiid_template_t tmpl,const char * field)559 fiid_template_field_len (fiid_template_t tmpl,
560                          const char *field)
561 {
562   if (!tmpl || !field)
563     {
564       /* FIID_ERR_PARAMETERS */
565       errno = EINVAL;
566       return (-1);
567     }
568 
569 #ifndef NDEBUG
570   if (_fiid_template_check_valid_keys (tmpl) < 0)
571     {
572       /* FIID_ERR_PARAMETERS */
573       errno = EINVAL;
574       return (-1);
575     }
576 #endif /* NDEBUG */
577 
578   return (_fiid_template_field_len (tmpl, field));
579 }
580 
581 int
fiid_template_field_len_bytes(fiid_template_t tmpl,const char * field)582 fiid_template_field_len_bytes (fiid_template_t tmpl,
583                                const char *field)
584 {
585   int len;
586 
587   if (!tmpl || !field)
588     {
589       /* FIID_ERR_PARAMETERS */
590       errno = EINVAL;
591       return (-1);
592     }
593 
594 #ifndef NDEBUG
595   if (_fiid_template_check_valid_keys (tmpl) < 0)
596     {
597       /* FIID_ERR_PARAMETERS */
598       errno = EINVAL;
599       return (-1);
600     }
601 #endif /* NDEBUG */
602 
603   if ((len = _fiid_template_field_len (tmpl,
604                                        field)) < 0)
605     return (-1);
606 
607   if (len % 8)
608     {
609       /* FIID_ERR_FIELD_NOT_BYTE_ALIGNED */
610       errno = EINVAL;
611       return (-1);
612     }
613 
614   return (BITS_ROUND_BYTES (len));
615 }
616 
617 static int
_fiid_template_block_len(fiid_template_t tmpl,const char * field_start,const char * field_end)618 _fiid_template_block_len (fiid_template_t tmpl,
619                           const char *field_start,
620                           const char *field_end)
621 {
622   int start;
623   int end;
624 
625   assert (tmpl);
626   assert (field_start);
627   assert (field_end);
628 
629   if ((end = _fiid_template_field_end (tmpl,
630                                        field_end)) < 0)
631     return (-1);
632 
633   if ((start = _fiid_template_field_start (tmpl,
634                                            field_start)) < 0)
635     return (-1);
636 
637   if (start > end)
638     {
639       /* FIID_ERR_PARAMETERS */
640       errno = EINVAL;
641       return (-1);
642     }
643 
644   return (end - start);
645 }
646 
647 int
fiid_template_block_len(fiid_template_t tmpl,const char * field_start,const char * field_end)648 fiid_template_block_len (fiid_template_t tmpl,
649                          const char *field_start,
650                          const char *field_end)
651 {
652   if (!tmpl || !field_start || !field_end)
653     {
654       /* FIID_ERR_PARAMETERS */
655       errno = EINVAL;
656       return (-1);
657     }
658 
659 #ifndef NDEBUG
660   if (_fiid_template_check_valid_keys (tmpl) < 0)
661     {
662       /* FIID_ERR_PARAMETERS */
663       errno = EINVAL;
664       return (-1);
665     }
666 #endif /* NDEBUG */
667 
668   return (_fiid_template_block_len (tmpl, field_start, field_end));
669 }
670 
671 int
fiid_template_block_len_bytes(fiid_template_t tmpl,const char * field_start,const char * field_end)672 fiid_template_block_len_bytes (fiid_template_t tmpl,
673                                const char *field_start,
674                                const char *field_end)
675 {
676   int len;
677 
678   if (!tmpl || !field_start || !field_end)
679     {
680       /* FIID_ERR_PARAMETERS */
681       errno = EINVAL;
682       return (-1);
683     }
684 
685 #ifndef NDEBUG
686   if (_fiid_template_check_valid_keys (tmpl) < 0)
687     {
688       /* FIID_ERR_PARAMETERS */
689       errno = EINVAL;
690       return (-1);
691     }
692 #endif /* NDEBUG */
693 
694   if ((len = _fiid_template_block_len (tmpl,
695                                        field_start,
696                                        field_end)) < 0)
697     return (-1);
698 
699   if (len % 8)
700     {
701       /* FIID_ERR_BLOCK_NOT_BYTE_ALIGNED */
702       errno = EINVAL;
703       return (-1);
704     }
705 
706   return (BITS_ROUND_BYTES (len));
707 }
708 
709 int
fiid_template_compare(fiid_template_t tmpl1,fiid_template_t tmpl2)710 fiid_template_compare (fiid_template_t tmpl1,
711                        fiid_template_t tmpl2)
712 {
713   unsigned int i;
714 
715   if (!tmpl1 || !tmpl2)
716     {
717       /* FIID_ERR_PARAMETERS */
718       errno = EINVAL;
719       return (-1);
720     }
721 
722 #ifndef NDEBUG
723   if (_fiid_template_check_valid_keys (tmpl1) < 0)
724     {
725       /* FIID_ERR_PARAMETERS */
726       errno = EINVAL;
727       return (-1);
728     }
729 #endif /* NDEBUG */
730 
731 #ifndef NDEBUG
732   if (_fiid_template_check_valid_keys (tmpl2) < 0)
733     {
734       /* FIID_ERR_PARAMETERS */
735       errno = EINVAL;
736       return (-1);
737     }
738 #endif /* NDEBUG */
739 
740   for (i = 0; tmpl1[i].max_field_len; i++)
741     {
742       if (tmpl1[i].max_field_len != tmpl2[i].max_field_len)
743         return (0);
744 
745       if (strcmp (tmpl1[i].key, tmpl2[i].key))
746         return (0);
747 
748       if (tmpl1[i].flags != tmpl2[i].flags)
749         return (0);
750     }
751 
752   if (tmpl2[i].max_field_len)
753     return (0);
754 
755   return (1);
756 }
757 
758 int
FIID_TEMPLATE_COMPARE(fiid_template_t tmpl1,fiid_template_t tmpl2)759 FIID_TEMPLATE_COMPARE (fiid_template_t tmpl1,
760                        fiid_template_t tmpl2)
761 {
762   int ret;
763 
764   if ((ret = fiid_template_compare (tmpl1, tmpl2)) < 0)
765     return (ret);
766 
767   if (!ret)
768     {
769       errno = EINVAL;
770       return (-1);
771     }
772 
773   return (ret);
774 }
775 
776 void
fiid_template_free(fiid_field_t * tmpl_dynamic)777 fiid_template_free (fiid_field_t *tmpl_dynamic)
778 {
779   free (tmpl_dynamic);
780 }
781 
782 static int
_fiid_obj_field_start_end(fiid_obj_t obj,const char * field,unsigned int * start,unsigned int * end)783 _fiid_obj_field_start_end (fiid_obj_t obj,
784                            const char *field,
785                            unsigned int *start,
786                            unsigned int *end)
787 {
788   struct fiid_field_data *ffdptr;
789   unsigned int i;
790 
791   assert (obj);
792   assert (obj->magic == FIID_OBJ_MAGIC);
793   assert (field);
794   assert (start);
795   assert (end);
796 
797   if ((ffdptr = hash_find (obj->lookup, field)))
798     {
799       *start = ffdptr->start;
800       *end = ffdptr->end;
801       return (ffdptr->max_field_len);
802     }
803 
804   /* integer overflow conditions checked during object creation */
805   for (i = 0; obj->field_data[i].max_field_len; i++)
806     {
807       if (!strcmp (obj->field_data[i].key, field))
808         {
809           if (!hash_insert (obj->lookup,
810                             obj->field_data[i].key,
811                             &(obj->field_data[i])))
812             {
813               obj->errnum = FIID_ERR_INTERNAL_ERROR;
814               return (-1);
815             }
816 
817           *start = obj->field_data[i].start;
818           *end = obj->field_data[i].end;
819           return (obj->field_data[i].max_field_len);
820         }
821     }
822 
823   obj->errnum = FIID_ERR_FIELD_NOT_FOUND;
824   return (-1);
825 }
826 
827 static int
_fiid_obj_field_start(fiid_obj_t obj,const char * field)828 _fiid_obj_field_start (fiid_obj_t obj, const char *field)
829 {
830   unsigned int start = 0;
831   unsigned int end = 0; /* excluded always */
832 
833   assert (obj);
834   assert (obj->magic == FIID_OBJ_MAGIC);
835   assert (field);
836 
837   if (_fiid_obj_field_start_end (obj, field, &start, &end) < 0)
838     return (-1);
839 
840   return (start);
841 }
842 
843 static int
_fiid_obj_field_end(fiid_obj_t obj,const char * field)844 _fiid_obj_field_end (fiid_obj_t obj, const char *field)
845 {
846   unsigned int start = 0;
847   unsigned int end = 0; /* excluded always */
848 
849   assert (obj);
850   assert (obj->magic == FIID_OBJ_MAGIC);
851   assert (field);
852 
853   if (_fiid_obj_field_start_end (obj, field, &start, &end) < 0)
854     return (-1);
855 
856   return (end);
857 }
858 
859 static int
_fiid_obj_field_len(fiid_obj_t obj,const char * field)860 _fiid_obj_field_len (fiid_obj_t obj, const char *field)
861 {
862   struct fiid_field_data *ffdptr;
863   unsigned int i;
864 
865   assert (obj);
866   assert (obj->magic == FIID_OBJ_MAGIC);
867   assert (field);
868 
869   if ((ffdptr = hash_find (obj->lookup, field)))
870     return (ffdptr->max_field_len);
871 
872   for (i = 0; obj->field_data[i].max_field_len; i++)
873     {
874       if (!strcmp (obj->field_data[i].key, field))
875         {
876           if (!hash_insert (obj->lookup,
877                             obj->field_data[i].key,
878                             &(obj->field_data[i])))
879             {
880               obj->errnum = FIID_ERR_INTERNAL_ERROR;
881               return (-1);
882             }
883 
884           return (obj->field_data[i].max_field_len);
885         }
886     }
887 
888   obj->errnum = FIID_ERR_FIELD_NOT_FOUND;
889   return (-1);
890 }
891 
892 char *
fiid_strerror(fiid_err_t errnum)893 fiid_strerror (fiid_err_t errnum)
894 {
895   if (errnum >= FIID_ERR_SUCCESS && errnum <= FIID_ERR_ERRNUMRANGE)
896     return (fiid_errmsg[errnum]);
897   else
898     return (fiid_errmsg[FIID_ERR_ERRNUMRANGE]);
899 }
900 
901 fiid_obj_t
fiid_obj_create(fiid_template_t tmpl)902 fiid_obj_create (fiid_template_t tmpl)
903 {
904   fiid_obj_t obj = NULL;
905   unsigned int max_pkt_len = 0;
906   unsigned int i;
907   unsigned int start = 0;
908   int data_len;
909 
910   if (!tmpl)
911     {
912       /* FIID_ERR_PARAMETERS */
913       errno = EINVAL;
914       goto cleanup;
915     }
916 
917 #ifndef NDEBUG
918   if (_fiid_template_check_valid_keys (tmpl) < 0)
919     {
920       /* FIID_ERR_TEMPLATE_INVALID */
921       errno = EINVAL;
922       goto cleanup;
923     }
924 #endif /* NDEBUG */
925 
926   if (_fiid_template_check_valid_flags (tmpl) < 0)
927     {
928       /* FIID_ERR_TEMPLATE_INVALID */
929       errno = EINVAL;
930       goto cleanup;
931     }
932 
933   if (!(obj = (fiid_obj_t)malloc (sizeof (struct fiid_obj))))
934     {
935       /* FIID_ERR_OUT_OF_MEMORY */
936       errno = ENOMEM;
937       goto cleanup;
938     }
939   memset (obj, '\0', sizeof (struct fiid_obj));
940   obj->magic = FIID_OBJ_MAGIC;
941 
942   /* after call to _fiid_template_len_bytes, we know each field length
943    * and total field length won't overflow an int.
944    */
945   if ((data_len = _fiid_template_len_bytes (tmpl,
946                                             &obj->field_data_len)) < 0)
947     goto cleanup;
948   obj->data_len = data_len;
949 
950   if (!obj->field_data_len)
951     {
952       /* FIID_ERR_TEMPLATE_INVALID */
953       errno = EINVAL;
954       goto cleanup;
955     }
956 
957   if (!(obj->data = malloc (obj->data_len)))
958     {
959       /* FIID_ERR_OUT_OF_MEMORY */
960       errno = ENOMEM;
961       goto cleanup;
962     }
963   memset (obj->data, '\0', obj->data_len);
964 
965   if (!(obj->field_data = malloc (obj->field_data_len * sizeof (struct fiid_field_data))))
966     {
967       /* FIID_ERR_OUT_OF_MEMORY */
968       errno = ENOMEM;
969       goto cleanup;
970     }
971   memset (obj->field_data, '\0', obj->field_data_len * sizeof (struct fiid_field_data));
972 
973   if (!(obj->lookup = hash_create (obj->field_data_len,
974                                    (hash_key_f)hash_key_string,
975                                    (hash_cmp_f)strcmp,
976                                    NULL)))
977     {
978       errno = ENOMEM;
979       goto cleanup;
980     }
981 
982   for (i = 0; i < obj->field_data_len; i++)
983     {
984 #ifndef NDEBUG
985       if (tmpl[i].max_field_len)
986         {
987           unsigned int j;
988 
989           for (j = 0; j < i; j++)
990             {
991               if (!strncmp (obj->field_data[j].key, tmpl[i].key, FIID_FIELD_MAX_KEY_LEN))
992                 {
993                   /* FIID_ERR_TEMPLATE_INVALID */
994                   errno = EINVAL;
995                   goto cleanup;
996                 }
997             }
998         }
999 #endif /* !NDEBUG */
1000       obj->field_data[i].max_field_len = tmpl[i].max_field_len;
1001       memset (obj->field_data[i].key, '\0', FIID_FIELD_MAX_KEY_LEN + 1);
1002       strncpy (obj->field_data[i].key, tmpl[i].key, FIID_FIELD_MAX_KEY_LEN);
1003       obj->field_data[i].set_field_len = 0;
1004       obj->field_data[i].flags = tmpl[i].flags;
1005       obj->field_data[i].index = i;
1006       obj->field_data[i].start = start;
1007       obj->field_data[i].end = start + obj->field_data[i].max_field_len;
1008       max_pkt_len += tmpl[i].max_field_len;
1009 
1010       if (obj->field_data[i].flags & FIID_FIELD_MAKES_PACKET_SUFFICIENT)
1011         obj->makes_packet_sufficient = 1;
1012 
1013       if (obj->field_data[i].flags & FIID_FIELD_SECURE_MEMSET_ON_CLEAR)
1014         obj->secure_memset_on_clear = 1;
1015 
1016       start += obj->field_data[i].max_field_len;
1017     }
1018 
1019   if (max_pkt_len % 8)
1020     {
1021       /* FIID_ERR_TEMPLATE_NOT_BYTE_ALIGNED */
1022       errno = EINVAL;
1023       goto cleanup;
1024     }
1025 
1026   obj->errnum = FIID_ERR_SUCCESS;
1027   return (obj);
1028 
1029  cleanup:
1030   if (obj)
1031     {
1032       free (obj->data);
1033       free (obj->field_data);
1034       hash_destroy (obj->lookup);
1035       free (obj);
1036     }
1037 
1038   return (NULL);
1039 }
1040 
1041 void
fiid_obj_destroy(fiid_obj_t obj)1042 fiid_obj_destroy (fiid_obj_t obj)
1043 {
1044   if (!(obj && obj->magic == FIID_OBJ_MAGIC))
1045     return;
1046 
1047   obj->magic = ~FIID_OBJ_MAGIC;
1048   obj->errnum = FIID_ERR_SUCCESS;
1049   free (obj->data);
1050   free (obj->field_data);
1051   hash_destroy (obj->lookup);
1052   free (obj);
1053 }
1054 
1055 fiid_obj_t
fiid_obj_dup(fiid_obj_t src_obj)1056 fiid_obj_dup (fiid_obj_t src_obj)
1057 {
1058   fiid_obj_t dest_obj = NULL;
1059 
1060   if (!src_obj || src_obj->magic != FIID_OBJ_MAGIC)
1061     goto cleanup;
1062 
1063   if (!(dest_obj = malloc (sizeof (struct fiid_obj))))
1064     {
1065       src_obj->errnum = FIID_ERR_OUT_OF_MEMORY;
1066       goto cleanup;
1067     }
1068   memset (dest_obj, '\0', sizeof (struct fiid_obj));
1069   dest_obj->magic = src_obj->magic;
1070   dest_obj->data_len = src_obj->data_len;
1071   dest_obj->field_data_len = src_obj->field_data_len;
1072 
1073   if (!(dest_obj->data = malloc (src_obj->data_len)))
1074     {
1075       src_obj->errnum = FIID_ERR_OUT_OF_MEMORY;
1076       goto cleanup;
1077     }
1078   memcpy (dest_obj->data, src_obj->data, src_obj->data_len);
1079 
1080   if (!(dest_obj->field_data = malloc (dest_obj->field_data_len * sizeof (struct fiid_field_data))))
1081     {
1082       src_obj->errnum = FIID_ERR_OUT_OF_MEMORY;
1083       goto cleanup;
1084     }
1085 
1086   memcpy (dest_obj->field_data,
1087           src_obj->field_data,
1088           src_obj->field_data_len * sizeof (struct fiid_field_data));
1089 
1090   if (!(dest_obj->lookup = hash_create (dest_obj->field_data_len,
1091                                         (hash_key_f)hash_key_string,
1092                                         (hash_cmp_f)strcmp,
1093                                         NULL)))
1094     {
1095       src_obj->errnum = FIID_ERR_OUT_OF_MEMORY;
1096       goto cleanup;
1097     }
1098 
1099   src_obj->errnum = FIID_ERR_SUCCESS;
1100   dest_obj->errnum = FIID_ERR_SUCCESS;
1101   return (dest_obj);
1102 
1103  cleanup:
1104   if (dest_obj)
1105     {
1106       free (dest_obj->data);
1107       free (dest_obj->field_data);
1108       hash_destroy (dest_obj->lookup);
1109       free (dest_obj);
1110     }
1111   return (NULL);
1112 }
1113 
1114 fiid_obj_t
fiid_obj_copy(fiid_obj_t src_obj,fiid_template_t alt_tmpl)1115 fiid_obj_copy (fiid_obj_t src_obj, fiid_template_t alt_tmpl)
1116 {
1117   fiid_obj_t dest_obj = NULL;
1118   int data_len;
1119   unsigned int field_data_len = 0;
1120   uint8_t *databuf = NULL;
1121 
1122   if (!src_obj || src_obj->magic != FIID_OBJ_MAGIC)
1123     goto cleanup;
1124 
1125   if ((data_len = _fiid_template_len_bytes (alt_tmpl, &field_data_len)) < 0)
1126     goto cleanup;
1127 
1128   if (src_obj->data_len != data_len)
1129     {
1130       src_obj->errnum = FIID_ERR_PARAMETERS;
1131       goto cleanup;
1132     }
1133 
1134   if (!(dest_obj = fiid_obj_create (alt_tmpl)))
1135     goto cleanup;
1136 
1137   if (!(databuf = (uint8_t *)malloc (src_obj->data_len)))
1138     {
1139       src_obj->errnum = FIID_ERR_OUT_OF_MEMORY;
1140       goto cleanup;
1141     }
1142 
1143   if ((data_len = fiid_obj_get_all (src_obj, databuf, src_obj->data_len)) < 0)
1144     goto cleanup;
1145 
1146   if (fiid_obj_set_all (dest_obj, databuf, data_len) < 0)
1147     {
1148       src_obj->errnum = dest_obj->errnum;
1149       goto cleanup;
1150     }
1151 
1152   free (databuf);
1153   return (dest_obj);
1154 
1155  cleanup:
1156   if (dest_obj)
1157     fiid_obj_destroy (dest_obj);
1158   free (databuf);
1159   return (NULL);
1160 }
1161 
1162 int
fiid_obj_valid(fiid_obj_t obj)1163 fiid_obj_valid (fiid_obj_t obj)
1164 {
1165   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1166     return (0);
1167   return (1);
1168 }
1169 
1170 static int
_fiid_obj_packet_valid(fiid_obj_t obj,int makes_packet_sufficient_checks)1171 _fiid_obj_packet_valid (fiid_obj_t obj, int makes_packet_sufficient_checks)
1172 {
1173   unsigned int total_set_bits_counter = 0, max_bits_counter = 0,
1174     set_bits_counter = 0, optional_bits_counter = 0;
1175   unsigned int i;
1176 
1177   assert (obj);
1178   assert (obj->magic == FIID_OBJ_MAGIC);
1179   assert (!makes_packet_sufficient_checks || obj->makes_packet_sufficient);
1180 
1181   for (i = 0; i < obj->field_data_len; i++)
1182     {
1183       unsigned int required_flag = FIID_FIELD_REQUIRED_FLAG (obj->field_data[i].flags);
1184       unsigned int length_flag = FIID_FIELD_LENGTH_FLAG (obj->field_data[i].flags);
1185       unsigned int max_field_len = obj->field_data[i].max_field_len;
1186       unsigned int set_field_len = obj->field_data[i].set_field_len;
1187       unsigned int makes_packet_sufficient_flag = obj->field_data[i].flags & FIID_FIELD_MAKES_PACKET_SUFFICIENT;
1188 
1189       if (makes_packet_sufficient_checks)
1190         {
1191           /* Each field w/ MAKES_PACKET_SUFFICIENT must have the field set. */
1192           if (makes_packet_sufficient_flag)
1193             {
1194               if (!set_field_len)
1195                 return (0);
1196 
1197               if (length_flag == FIID_FIELD_LENGTH_FIXED && max_field_len != set_field_len)
1198                 return (0);
1199             }
1200         }
1201       else
1202         {
1203           if (required_flag == FIID_FIELD_REQUIRED && !set_field_len)
1204             {
1205               obj->errnum = FIID_ERR_REQUIRED_FIELD_MISSING;
1206               return (0);
1207             }
1208 
1209           if ((length_flag == FIID_FIELD_LENGTH_FIXED && max_field_len != set_field_len)
1210               && (required_flag == FIID_FIELD_REQUIRED
1211                   || (required_flag == FIID_FIELD_OPTIONAL && set_field_len)))
1212 
1213             {
1214               obj->errnum = FIID_ERR_FIXED_LENGTH_FIELD_INVALID;
1215               return (0);
1216             }
1217         }
1218 
1219       max_bits_counter += max_field_len;
1220       total_set_bits_counter += set_field_len;
1221 
1222       if (set_field_len)
1223         {
1224           if (optional_bits_counter)
1225             {
1226               obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1227               return (0);
1228             }
1229 
1230           if (set_field_len != max_field_len)
1231             {
1232               /* If there is an optional or variable length
1233                * field, it cannot have only partial data.
1234                */
1235               if ((set_bits_counter + set_field_len) % 8)
1236                 {
1237                   obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1238                   return (0);
1239                 }
1240             }
1241 
1242           set_bits_counter += set_field_len;
1243           if (!(set_bits_counter % 8))
1244             {
1245               set_bits_counter = 0;
1246               max_bits_counter = 0;
1247             }
1248         }
1249       else
1250         {
1251           /* All information must be collected in byte sized
1252            * chunks
1253            */
1254           if (set_bits_counter)
1255             {
1256               obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1257               return (0);
1258             }
1259 
1260           /* Likewise, optional data should be aligned across
1261            * bytes
1262            */
1263           optional_bits_counter += max_field_len;
1264           if (optional_bits_counter && !(optional_bits_counter % 8))
1265             {
1266               /* an "assert" */
1267               if (optional_bits_counter != max_bits_counter)
1268                 {
1269                   obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1270                   return (0);
1271                 }
1272 
1273               optional_bits_counter = 0;
1274               max_bits_counter = 0;
1275             }
1276         }
1277     }
1278 
1279   /* There shouldn't be anything left over */
1280   if (set_bits_counter)
1281     {
1282       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1283       return (0);
1284     }
1285 
1286   /* And the bits set should align across a byte */
1287   if (total_set_bits_counter % 8)
1288     {
1289       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1290       return (0);
1291     }
1292 
1293   obj->errnum = FIID_ERR_SUCCESS;
1294   return (1);
1295 }
1296 
1297 int
fiid_obj_packet_valid(fiid_obj_t obj)1298 fiid_obj_packet_valid (fiid_obj_t obj)
1299 {
1300   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1301     return (-1);
1302 
1303   return _fiid_obj_packet_valid (obj, 0);
1304 }
1305 
1306 int
FIID_OBJ_PACKET_VALID(fiid_obj_t obj)1307 FIID_OBJ_PACKET_VALID (fiid_obj_t obj)
1308 {
1309   int ret;
1310 
1311   if ((ret = fiid_obj_packet_valid (obj)) < 0)
1312     return (ret);
1313 
1314   /* errnum set in fiid_obj_packet_valid() */
1315   if (!ret)
1316     return (-1);
1317 
1318   return (ret);
1319 }
1320 
1321 int
fiid_obj_packet_sufficient(fiid_obj_t obj)1322 fiid_obj_packet_sufficient (fiid_obj_t obj)
1323 {
1324   int ret;
1325 
1326   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1327     return (-1);
1328 
1329   if (!obj->makes_packet_sufficient)
1330     return _fiid_obj_packet_valid (obj, 0);
1331 
1332   if (!(ret = _fiid_obj_packet_valid (obj, 0)))
1333     {
1334       fiid_err_t save_errnum = obj->errnum;
1335 
1336       if (_fiid_obj_packet_valid (obj, 1) == 1)
1337         return (1);
1338 
1339       obj->errnum = save_errnum;
1340     }
1341   return (ret);
1342 }
1343 
1344 int
FIID_OBJ_PACKET_SUFFICIENT(fiid_obj_t obj)1345 FIID_OBJ_PACKET_SUFFICIENT (fiid_obj_t obj)
1346 {
1347   int ret;
1348 
1349   if ((ret = fiid_obj_packet_sufficient (obj)) < 0)
1350     return (ret);
1351 
1352   /* errnum set in fiid_obj_packet_sufficient() */
1353   if (!ret)
1354     return (-1);
1355 
1356   return (ret);
1357 }
1358 
1359 fiid_field_t *
fiid_obj_template(fiid_obj_t obj)1360 fiid_obj_template (fiid_obj_t obj)
1361 {
1362   fiid_field_t *tmpl;
1363   unsigned int i;
1364 
1365   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1366     return (NULL);
1367 
1368   if (!(tmpl = (fiid_field_t *)malloc (sizeof (fiid_field_t) * obj->field_data_len)))
1369     {
1370       obj->errnum = FIID_ERR_OUT_OF_MEMORY;
1371       return (NULL);
1372     }
1373   memset (tmpl, '\0', sizeof (fiid_field_t) * obj->field_data_len);
1374 
1375   for (i = 0; i < obj->field_data_len; i++)
1376     {
1377       tmpl[i].max_field_len = obj->field_data[i].max_field_len;
1378       /* not FIID_FIELD_MAX_KEY_LEN + 1, template does not have + 1 */
1379       memcpy (tmpl[i].key, obj->field_data[i].key, FIID_FIELD_MAX_KEY_LEN);
1380       tmpl[i].flags = obj->field_data[i].flags;
1381     }
1382 
1383   obj->errnum = FIID_ERR_SUCCESS;
1384   return (tmpl);
1385 }
1386 
1387 int
fiid_obj_template_compare(fiid_obj_t obj,fiid_template_t tmpl)1388 fiid_obj_template_compare (fiid_obj_t obj, fiid_template_t tmpl)
1389 {
1390   unsigned int i;
1391 
1392   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1393     return (-1);
1394 
1395   if (!tmpl)
1396     {
1397       obj->errnum = FIID_ERR_PARAMETERS;
1398       return (-1);
1399     }
1400 
1401 #ifndef NDEBUG
1402   if (_fiid_template_check_valid_keys (tmpl) < 0)
1403     {
1404       obj->errnum = FIID_ERR_TEMPLATE_INVALID;
1405       return (-1);
1406     }
1407 #endif /* NDEBUG */
1408 
1409   for (i = 0; obj->field_data[i].max_field_len; i++)
1410     {
1411       if (obj->field_data[i].max_field_len != tmpl[i].max_field_len)
1412         {
1413           obj->errnum = FIID_ERR_MAX_FIELD_LEN_MISMATCH;
1414           return (0);
1415         }
1416 
1417       if (strcmp (obj->field_data[i].key, tmpl[i].key))
1418         {
1419           obj->errnum = FIID_ERR_KEY_FIELD_MISMATCH;
1420           return (0);
1421         }
1422 
1423       if (obj->field_data[i].flags != tmpl[i].flags)
1424         {
1425           obj->errnum = FIID_ERR_FLAGS_FIELD_MISMATCH;
1426           return (0);
1427         }
1428     }
1429 
1430   if (tmpl[i].max_field_len)
1431     {
1432       obj->errnum = FIID_ERR_TEMPLATE_LENGTH_MISMATCH;
1433       return (0);
1434     }
1435 
1436   obj->errnum = FIID_ERR_SUCCESS;
1437   return (1);
1438 }
1439 
1440 int
FIID_OBJ_TEMPLATE_COMPARE(fiid_obj_t obj,fiid_template_t tmpl)1441 FIID_OBJ_TEMPLATE_COMPARE (fiid_obj_t obj, fiid_template_t tmpl)
1442 {
1443   int ret;
1444 
1445   if ((ret = fiid_obj_template_compare (obj, tmpl)) < 0)
1446     return (ret);
1447 
1448   if (!ret)
1449     {
1450       obj->errnum = FIID_ERR_NOT_IDENTICAL;
1451       return (-1);
1452     }
1453 
1454   return (ret);
1455 }
1456 
1457 fiid_err_t
fiid_obj_errnum(fiid_obj_t obj)1458 fiid_obj_errnum (fiid_obj_t obj)
1459 {
1460   if (!obj)
1461     return (FIID_ERR_OBJ_NULL);
1462   else if (obj->magic != FIID_OBJ_MAGIC)
1463     return (FIID_ERR_OBJ_INVALID);
1464   else
1465     return (obj->errnum);
1466 }
1467 
1468 char *
fiid_obj_errormsg(fiid_obj_t obj)1469 fiid_obj_errormsg (fiid_obj_t obj)
1470 {
1471   return (fiid_strerror (fiid_obj_errnum (obj)));
1472 }
1473 
1474 static int
_fiid_obj_lookup_field_index(fiid_obj_t obj,const char * field,unsigned int * index)1475 _fiid_obj_lookup_field_index (fiid_obj_t obj, const char *field, unsigned int *index)
1476 {
1477   struct fiid_field_data *ffdptr;
1478   unsigned int i;
1479 
1480   assert (obj);
1481   assert (obj->magic == FIID_OBJ_MAGIC);
1482   assert (field);
1483   assert (index);
1484 
1485   if ((ffdptr = hash_find (obj->lookup, field)))
1486     {
1487       (*index) = ffdptr->index;
1488       return (0);
1489     }
1490 
1491   for (i = 0; obj->field_data[i].max_field_len; i++)
1492     {
1493       if (!strcmp (obj->field_data[i].key, field))
1494         {
1495           if (!hash_insert (obj->lookup,
1496                             obj->field_data[i].key,
1497                             &(obj->field_data[i])))
1498             {
1499               obj->errnum = FIID_ERR_INTERNAL_ERROR;
1500               return (-1);
1501             }
1502 
1503           (*index) = obj->field_data[i].index;
1504           return (0);
1505         }
1506     }
1507 
1508   obj->errnum = FIID_ERR_FIELD_NOT_FOUND;
1509   return (-1);
1510 }
1511 
1512 int
fiid_obj_len(fiid_obj_t obj)1513 fiid_obj_len (fiid_obj_t obj)
1514 {
1515   unsigned int counter = 0;
1516   unsigned int i;
1517 
1518   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1519     return (-1);
1520 
1521   /* integer overflow conditions checked during object creation */
1522   for (i = 0; obj->field_data[i].max_field_len; i++)
1523     counter += obj->field_data[i].set_field_len;
1524 
1525   obj->errnum = FIID_ERR_SUCCESS;
1526   return (counter);
1527 }
1528 
1529 int
fiid_obj_len_bytes(fiid_obj_t obj)1530 fiid_obj_len_bytes (fiid_obj_t obj)
1531 {
1532   int len;
1533 
1534   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1535     return (-1);
1536 
1537   if ((len = fiid_obj_len (obj)) < 0)
1538     return (-1);
1539 
1540   if (len % 8)
1541     {
1542       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1543       return (-1);
1544     }
1545 
1546   obj->errnum = FIID_ERR_SUCCESS;
1547   return (BITS_ROUND_BYTES (len));
1548 }
1549 
1550 int
fiid_obj_field_len(fiid_obj_t obj,const char * field)1551 fiid_obj_field_len (fiid_obj_t obj, const char *field)
1552 {
1553   unsigned int key_index;
1554 
1555   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1556     return (-1);
1557 
1558   if (!field)
1559     {
1560       obj->errnum = FIID_ERR_PARAMETERS;
1561       return (-1);
1562     }
1563 
1564   if (_fiid_obj_lookup_field_index (obj, field, &key_index) < 0)
1565     return (-1);
1566 
1567   obj->errnum = FIID_ERR_SUCCESS;
1568   return (obj->field_data[key_index].set_field_len);
1569 }
1570 
1571 int
fiid_obj_field_len_bytes(fiid_obj_t obj,const char * field)1572 fiid_obj_field_len_bytes (fiid_obj_t obj, const char *field)
1573 {
1574   int len;
1575 
1576   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1577     return (-1);
1578 
1579   if (!field)
1580     {
1581       obj->errnum = FIID_ERR_PARAMETERS;
1582       return (-1);
1583     }
1584 
1585   if ((len = fiid_obj_field_len (obj, field)) < 0)
1586     return (-1);
1587 
1588   if (len % 8)
1589     {
1590       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1591       return (-1);
1592     }
1593 
1594   obj->errnum = FIID_ERR_SUCCESS;
1595   return (BITS_ROUND_BYTES (len));
1596 }
1597 
1598 int
fiid_obj_block_len(fiid_obj_t obj,const char * field_start,const char * field_end)1599 fiid_obj_block_len (fiid_obj_t obj, const char *field_start, const char *field_end)
1600 {
1601   unsigned int key_index_start, key_index_end;
1602   unsigned int counter = 0;
1603   unsigned int i;
1604 
1605   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1606     return (-1);
1607 
1608   if (!field_start || !field_end)
1609     {
1610       obj->errnum = FIID_ERR_PARAMETERS;
1611       return (-1);
1612     }
1613 
1614   if (_fiid_obj_lookup_field_index (obj, field_start, &key_index_start) < 0)
1615     return (-1);
1616 
1617   if (_fiid_obj_lookup_field_index (obj, field_end, &key_index_end) < 0)
1618     return (-1);
1619 
1620   if (key_index_start > key_index_end)
1621     {
1622       obj->errnum = FIID_ERR_PARAMETERS;
1623       return (-1);
1624     }
1625 
1626   /* integer overflow conditions checked during object creation */
1627   for (i = key_index_start; i <= key_index_end; i++)
1628     counter += obj->field_data[i].set_field_len;
1629 
1630   obj->errnum = FIID_ERR_SUCCESS;
1631   return (counter);
1632 }
1633 
1634 int
fiid_obj_block_len_bytes(fiid_obj_t obj,const char * field_start,const char * field_end)1635 fiid_obj_block_len_bytes (fiid_obj_t obj, const char *field_start, const char *field_end)
1636 {
1637   int len;
1638 
1639   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1640     return (-1);
1641 
1642   if (!field_start || !field_end)
1643     {
1644       obj->errnum = FIID_ERR_PARAMETERS;
1645       return (-1);
1646     }
1647 
1648   if ((len = fiid_obj_block_len (obj, field_start, field_end)) < 0)
1649     return (-1);
1650 
1651   if (len % 8)
1652     {
1653       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1654       return (-1);
1655     }
1656 
1657   obj->errnum = FIID_ERR_SUCCESS;
1658   return (BITS_ROUND_BYTES (len));
1659 }
1660 
1661 int
fiid_obj_clear(fiid_obj_t obj)1662 fiid_obj_clear (fiid_obj_t obj)
1663 {
1664   unsigned int i;
1665 
1666   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1667     return (-1);
1668 
1669   if (obj->secure_memset_on_clear)
1670     secure_memset (obj->data, '\0', obj->data_len);
1671   else
1672     memset (obj->data, '\0', obj->data_len);
1673 
1674   for (i =0; i < obj->field_data_len; i++)
1675     obj->field_data[i].set_field_len = 0;
1676 
1677   obj->errnum = FIID_ERR_SUCCESS;
1678   return (0);
1679 }
1680 
1681 int
fiid_obj_clear_field(fiid_obj_t obj,const char * field)1682 fiid_obj_clear_field (fiid_obj_t obj, const char *field)
1683 {
1684   unsigned int key_index;
1685   int bits_len;
1686 
1687   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1688     return (-1);
1689 
1690   if (!field)
1691     {
1692       obj->errnum = FIID_ERR_PARAMETERS;
1693       return (-1);
1694     }
1695 
1696   if (_fiid_obj_lookup_field_index (obj, field, &key_index) < 0)
1697     return (-1);
1698 
1699   if (!obj->field_data[key_index].set_field_len)
1700     return (0);
1701 
1702   if ((bits_len = _fiid_obj_field_len (obj, field)) < 0)
1703     return (-1);
1704 
1705   if (bits_len <= 64)
1706     {
1707       uint64_t val = 0;
1708 
1709       if (fiid_obj_set (obj, field, val) < 0)
1710         return (-1);
1711     }
1712   else
1713     {
1714       int field_start;
1715       unsigned int field_offset, bytes_len;
1716 
1717       /* achu: We assume the field must start on a byte boundary and end
1718        * on a byte boundary.
1719        */
1720 
1721       if (bits_len % 8)
1722         {
1723           obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1724           return (-1);
1725         }
1726 
1727       bytes_len = BITS_ROUND_BYTES (bits_len);
1728 
1729       if ((field_start = _fiid_obj_field_start (obj, field)) < 0)
1730         return (-1);
1731 
1732       if (field_start % 8)
1733         {
1734           obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
1735           return (-1);
1736         }
1737 
1738       field_offset = BITS_ROUND_BYTES (field_start);
1739       if (obj->field_data[key_index].flags & FIID_FIELD_SECURE_MEMSET_ON_CLEAR)
1740         secure_memset (obj->data + field_offset, '\0', bytes_len);
1741       else
1742         memset (obj->data + field_offset, '\0', bytes_len);
1743     }
1744 
1745   obj->field_data[key_index].set_field_len = 0;
1746   obj->errnum = FIID_ERR_SUCCESS;
1747   return (0);
1748 }
1749 
1750 int
fiid_obj_field_lookup(fiid_obj_t obj,const char * field)1751 fiid_obj_field_lookup (fiid_obj_t obj, const char *field)
1752 {
1753   unsigned int start = 0;
1754   unsigned int end = 0; /* excluded always */
1755 
1756   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1757     return (-1);
1758 
1759   if (!field)
1760     {
1761       obj->errnum = FIID_ERR_PARAMETERS;
1762       return (-1);
1763     }
1764 
1765   if (_fiid_obj_field_start_end (obj, field, &start, &end) != -1)
1766     {
1767       obj->errnum = FIID_ERR_SUCCESS;
1768       return (1);
1769     }
1770 
1771   obj->errnum = FIID_ERR_FIELD_NOT_FOUND;
1772   return (0);
1773 }
1774 
1775 int
FIID_OBJ_FIELD_LOOKUP(fiid_obj_t obj,const char * field)1776 FIID_OBJ_FIELD_LOOKUP (fiid_obj_t obj, const char *field)
1777 {
1778   int ret;
1779 
1780   if ((ret = fiid_obj_field_lookup (obj, field)) < 0)
1781     return (ret);
1782 
1783   if (!ret)
1784     {
1785       obj->errnum = FIID_ERR_FIELD_NOT_FOUND;
1786       return (-1);
1787     }
1788 
1789   return (ret);
1790 }
1791 
1792 int
fiid_obj_set(fiid_obj_t obj,const char * field,uint64_t val)1793 fiid_obj_set (fiid_obj_t obj,
1794               const char *field,
1795               uint64_t val)
1796 {
1797   unsigned int start_bit_pos = 0;
1798   unsigned int end_bit_pos = 0; /* excluded always */
1799   int byte_pos = 0;
1800   int start_bit_in_byte_pos = 0;
1801   int end_bit_in_byte_pos = 0;
1802   int field_len = 0;
1803   int bytes_used = 0;
1804   unsigned int key_index;
1805   uint64_t merged_val = 0;
1806   uint8_t *temp_data = NULL;
1807 
1808   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1809     goto cleanup;
1810 
1811   if (!field)
1812     {
1813       obj->errnum = FIID_ERR_PARAMETERS;
1814       goto cleanup;
1815     }
1816 
1817   if (_fiid_obj_lookup_field_index (obj, field, &key_index) < 0)
1818     return (-1);
1819 
1820   if ((field_len = _fiid_obj_field_start_end (obj,
1821                                               field,
1822                                               &start_bit_pos,
1823                                               &end_bit_pos)) < 0)
1824     return (-1);
1825 
1826   if (field_len > 64)
1827     field_len = 64;
1828 
1829   byte_pos = start_bit_pos / 8;
1830 
1831   /* in byte_pos, start_bit_pos is  */
1832   start_bit_in_byte_pos = start_bit_pos - (byte_pos * 8);
1833 
1834   /* and it spans into... */
1835   if (start_bit_in_byte_pos + field_len > 8)
1836     {
1837       int field_len_temp = field_len;
1838 
1839       if (start_bit_in_byte_pos)
1840         bytes_used++;
1841 
1842       field_len_temp -= start_bit_in_byte_pos;
1843 
1844       bytes_used += (field_len_temp / 8);
1845 
1846       field_len_temp -= (bytes_used * 8);
1847 
1848       if (field_len_temp)
1849         bytes_used++;
1850     }
1851   else
1852     {
1853       end_bit_in_byte_pos = start_bit_in_byte_pos + field_len;
1854       bytes_used++;
1855     }
1856 
1857   if (bytes_used > 1)
1858     {
1859       int start_val_pos = 0;
1860       int end_val_pos = 0;
1861       uint64_t extracted_val = 0;
1862       int field_len_left = field_len;
1863       unsigned int i;
1864 
1865       if (!(temp_data = malloc (obj->data_len)))
1866         {
1867           obj->errnum = FIID_ERR_OUT_OF_MEMORY;
1868           goto cleanup;
1869         }
1870       memcpy (temp_data, obj->data, obj->data_len);
1871 
1872       for (i = 0; i < bytes_used; i++)
1873         {
1874           if (i == 0)
1875             {
1876               end_val_pos = 8 - start_bit_in_byte_pos;
1877               field_len_left -= end_val_pos;
1878             }
1879           else if (i != (bytes_used - 1))
1880             {
1881               end_val_pos += 8;
1882               field_len_left -= 8;
1883             }
1884           else
1885             end_val_pos += field_len_left;
1886 
1887           if (i != (bytes_used - 1))
1888             end_bit_in_byte_pos = 8;
1889           else
1890             end_bit_in_byte_pos = field_len_left;
1891 
1892           if (bits_extract (val,
1893                             start_val_pos,
1894                             end_val_pos,
1895                             &extracted_val) < 0)
1896             {
1897               obj->errnum = FIID_ERR_INTERNAL_ERROR;
1898               goto cleanup;
1899             }
1900 
1901           if (bits_merge (temp_data[byte_pos + i],
1902                           start_bit_in_byte_pos,
1903                           end_bit_in_byte_pos,
1904                           extracted_val,
1905                           &merged_val) < 0)
1906             {
1907               obj->errnum = FIID_ERR_INTERNAL_ERROR;
1908               goto cleanup;
1909             }
1910 
1911           temp_data[byte_pos + i] = merged_val;
1912           start_bit_in_byte_pos = 0;
1913           start_val_pos = end_val_pos;
1914         }
1915 
1916       memcpy (obj->data, temp_data, obj->data_len);
1917       obj->field_data[key_index].set_field_len = field_len;
1918     }
1919   else
1920     {
1921       if (bits_merge (obj->data[byte_pos],
1922                       start_bit_in_byte_pos,
1923                       end_bit_in_byte_pos,
1924                       val,
1925                       &merged_val) < 0)
1926         {
1927           obj->errnum = FIID_ERR_INTERNAL_ERROR;
1928           goto cleanup;
1929         }
1930       obj->data[byte_pos] = merged_val;
1931       obj->field_data[key_index].set_field_len = field_len;
1932     }
1933 
1934   free (temp_data);
1935   obj->errnum = FIID_ERR_SUCCESS;
1936   return (0);
1937 
1938  cleanup:
1939   free (temp_data);
1940   return (-1);
1941 }
1942 
1943 int
fiid_obj_get(fiid_obj_t obj,const char * field,uint64_t * val)1944 fiid_obj_get (fiid_obj_t obj,
1945               const char *field,
1946               uint64_t *val)
1947 {
1948   unsigned int start_bit_pos = 0;
1949   unsigned int end_bit_pos = 0; /* excluded always */
1950   int byte_pos = 0;
1951   int start_bit_in_byte_pos = 0;
1952   int end_bit_in_byte_pos = 0;
1953   int field_len = 0;
1954   int bytes_used = 0;
1955   unsigned int key_index;
1956   uint64_t merged_val = 0;
1957 
1958   if (!obj || obj->magic != FIID_OBJ_MAGIC)
1959     return (-1);
1960 
1961   if (!field || !val)
1962     {
1963       obj->errnum = FIID_ERR_PARAMETERS;
1964       return (-1);
1965     }
1966 
1967   if (_fiid_obj_lookup_field_index (obj, field, &key_index) < 0)
1968     return (-1);
1969 
1970   if (!obj->field_data[key_index].set_field_len)
1971     {
1972       obj->errnum = FIID_ERR_SUCCESS;
1973       return (0);
1974     }
1975 
1976   if ((field_len = _fiid_obj_field_start_end (obj,
1977                                               field,
1978                                               &start_bit_pos,
1979                                               &end_bit_pos)) < 0)
1980     return (-1);
1981 
1982   if (field_len > 64)
1983     field_len = 64;
1984 
1985   if (field_len > obj->field_data[key_index].set_field_len)
1986     field_len = obj->field_data[key_index].set_field_len;
1987 
1988   byte_pos = start_bit_pos / 8;
1989 
1990   /* in byte_pos, start_bit_pos is  */
1991   start_bit_in_byte_pos = start_bit_pos - (byte_pos * 8);
1992 
1993   /* and it spans into... */
1994   if (start_bit_in_byte_pos + field_len > 8)
1995     {
1996       int field_len_temp = field_len;
1997 
1998       if (start_bit_in_byte_pos)
1999         bytes_used++;
2000 
2001       field_len_temp -= start_bit_in_byte_pos;
2002 
2003       bytes_used += (field_len_temp / 8);
2004 
2005       field_len_temp -= (bytes_used * 8);
2006 
2007       if (field_len_temp)
2008         bytes_used++;
2009     }
2010   else
2011     {
2012       end_bit_in_byte_pos = start_bit_in_byte_pos + field_len;
2013       bytes_used++;
2014     }
2015 
2016   if (bytes_used > 1)
2017     {
2018       int start_val_pos = 0;
2019       int end_val_pos = 0;
2020       uint64_t extracted_val = 0;
2021       uint64_t final_val = 0x0;
2022       int field_len_left = field_len;
2023       unsigned int i;
2024 
2025       for (i = 0; i < bytes_used; i++)
2026         {
2027           if (i == 0)
2028             {
2029               end_val_pos = 8 - start_bit_in_byte_pos;
2030               field_len_left -= end_val_pos;
2031             }
2032           else if (i != (bytes_used - 1))
2033             {
2034               end_val_pos += 8;
2035               field_len_left -= 8;
2036             }
2037           else
2038             end_val_pos += field_len_left;
2039 
2040           if (i != (bytes_used - 1))
2041             end_bit_in_byte_pos = 8;
2042           else
2043             end_bit_in_byte_pos = field_len_left;
2044 
2045           if (bits_extract (obj->data[byte_pos + i],
2046                             start_bit_in_byte_pos,
2047                             end_bit_in_byte_pos,
2048                             &extracted_val) < 0)
2049             {
2050               obj->errnum = FIID_ERR_INTERNAL_ERROR;
2051               return (-1);
2052             }
2053 
2054           if (bits_merge (final_val,
2055                           start_val_pos,
2056                           end_val_pos,
2057                           extracted_val,
2058                           &merged_val) < 0)
2059             {
2060               obj->errnum = FIID_ERR_INTERNAL_ERROR;
2061               return (-1);
2062             }
2063 
2064           final_val = merged_val;
2065           start_bit_in_byte_pos = 0;
2066           start_val_pos = end_val_pos;
2067         }
2068 
2069       *val = 0;
2070       *val = final_val;
2071     }
2072   else
2073     {
2074       if (bits_extract (obj->data[byte_pos],
2075                         start_bit_in_byte_pos,
2076                         end_bit_in_byte_pos,
2077                         &merged_val) < 0)
2078         {
2079           obj->errnum = FIID_ERR_INTERNAL_ERROR;
2080           return (-1);
2081         }
2082 
2083       *val = 0;
2084       *val = merged_val;
2085     }
2086 
2087   obj->errnum = FIID_ERR_SUCCESS;
2088   return (1);
2089 }
2090 
2091 int
FIID_OBJ_GET(fiid_obj_t obj,const char * field,uint64_t * val)2092 FIID_OBJ_GET (fiid_obj_t obj,
2093               const char *field,
2094               uint64_t *val)
2095 {
2096   uint64_t lval;
2097   int ret;
2098 
2099   if ((ret = fiid_obj_get (obj, field, &lval)) < 0)
2100     return (ret);
2101 
2102   if (!ret)
2103     {
2104       obj->errnum = FIID_ERR_DATA_NOT_AVAILABLE;
2105       return (-1);
2106     }
2107 
2108   *val = lval;
2109   return (ret);
2110 }
2111 
2112 int
fiid_obj_set_data(fiid_obj_t obj,const char * field,const void * data,unsigned int data_len)2113 fiid_obj_set_data (fiid_obj_t obj,
2114                    const char *field,
2115                    const void *data,
2116                    unsigned int data_len)
2117 {
2118   unsigned int field_offset, bytes_len, key_index;
2119   int bits_len, field_start;
2120 
2121   if (!obj || obj->magic != FIID_OBJ_MAGIC)
2122     return (-1);
2123 
2124   if (!field || !data)
2125     {
2126       obj->errnum = FIID_ERR_PARAMETERS;
2127       return (-1);
2128     }
2129 
2130   if (_fiid_obj_lookup_field_index (obj, field, &key_index) < 0)
2131     return (-1);
2132 
2133   /* achu: We assume the field must start on a byte boundary and end
2134    * on a byte boundary.
2135    */
2136 
2137   if ((field_start = _fiid_obj_field_start (obj, field)) < 0)
2138     return (-1);
2139 
2140   if (field_start % 8)
2141     {
2142       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2143       return (-1);
2144     }
2145 
2146   if ((bits_len = _fiid_obj_field_len (obj, field)) < 0)
2147     return (-1);
2148 
2149   if (bits_len % 8)
2150     {
2151       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2152       return (-1);
2153     }
2154 
2155   bytes_len = BITS_ROUND_BYTES (bits_len);
2156   if (data_len > bytes_len)
2157     data_len = bytes_len;
2158 
2159   field_offset = BITS_ROUND_BYTES (field_start);
2160   memcpy ((obj->data + field_offset), data, data_len);
2161   obj->field_data[key_index].set_field_len = (data_len * 8);
2162 
2163   obj->errnum = FIID_ERR_SUCCESS;
2164   return (data_len);
2165 }
2166 
2167 int
fiid_obj_get_data(fiid_obj_t obj,const char * field,void * data,unsigned int data_len)2168 fiid_obj_get_data (fiid_obj_t obj,
2169                    const char *field,
2170                    void *data,
2171                    unsigned int data_len)
2172 {
2173   unsigned int field_offset, bytes_len, key_index;
2174   int bits_len, field_start;
2175 
2176   if (!obj || obj->magic != FIID_OBJ_MAGIC)
2177     return (-1);
2178 
2179   if (!field || !data)
2180     {
2181       obj->errnum = FIID_ERR_PARAMETERS;
2182       return (-1);
2183     }
2184 
2185   if (_fiid_obj_lookup_field_index (obj, field, &key_index) < 0)
2186     return (-1);
2187 
2188   if (!obj->field_data[key_index].set_field_len)
2189     return (0);
2190 
2191   /* achu: We assume the field must start on a byte boundary and end
2192    * on a byte boundary.
2193    */
2194 
2195   if ((field_start = _fiid_obj_field_start (obj, field)) < 0)
2196     return (-1);
2197 
2198   if (field_start % 8)
2199     {
2200       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2201       return (-1);
2202     }
2203 
2204   if ((bits_len = _fiid_obj_field_len (obj, field)) < 0)
2205     return (-1);
2206 
2207   if (obj->field_data[key_index].set_field_len < bits_len)
2208     bits_len = obj->field_data[key_index].set_field_len;
2209 
2210   if (bits_len % 8)
2211     {
2212       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2213       return (-1);
2214     }
2215 
2216   bytes_len = BITS_ROUND_BYTES (bits_len);
2217 
2218   if (bytes_len > data_len)
2219     {
2220       obj->errnum = FIID_ERR_OVERFLOW;
2221       return (-1);
2222     }
2223 
2224   field_offset = BITS_ROUND_BYTES (field_start);
2225 
2226   memcpy (data, (obj->data + field_offset), bytes_len);
2227 
2228   obj->errnum = FIID_ERR_SUCCESS;
2229   return (bytes_len);
2230 }
2231 
2232 int
fiid_obj_set_all(fiid_obj_t obj,const void * data,unsigned int data_len)2233 fiid_obj_set_all (fiid_obj_t obj,
2234                   const void *data,
2235                   unsigned int data_len)
2236 {
2237   unsigned int bits_counter, data_bits_len;
2238   unsigned int key_index_end;
2239   unsigned int i;
2240 
2241   if (!obj || obj->magic != FIID_OBJ_MAGIC)
2242     return (-1);
2243 
2244   if (!data)
2245     {
2246       obj->errnum = FIID_ERR_PARAMETERS;
2247       return (-1);
2248     }
2249 
2250   if (data_len > obj->data_len)
2251     data_len = obj->data_len;
2252 
2253   /* achu: Find index of last field */
2254   data_bits_len = data_len * 8;
2255   if (data_len < obj->data_len)
2256     {
2257       /* integer overflow conditions checked during object creation */
2258       bits_counter = 0;
2259       for (i = 0; obj->field_data[i].max_field_len; i++)
2260         {
2261           bits_counter += obj->field_data[i].max_field_len;
2262           if (bits_counter >= data_bits_len)
2263             {
2264               /* achu: We assume the data must end on a byte boundary. */
2265               if (bits_counter % 8)
2266                 {
2267                   obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2268                   return (-1);
2269                 }
2270               else
2271                 break;
2272             }
2273 
2274         }
2275       key_index_end = i;
2276     }
2277   else
2278     key_index_end = (obj->field_data_len - 1);
2279 
2280   memcpy (obj->data, data, data_len);
2281 
2282   /* integer overflow conditions checked during object creation */
2283   bits_counter = 0;
2284   for (i = 0; i < key_index_end; i++)
2285     {
2286       obj->field_data[i].set_field_len = obj->field_data[i].max_field_len;
2287       bits_counter += obj->field_data[i].set_field_len;
2288     }
2289   if (data_bits_len < bits_counter + obj->field_data[key_index_end].max_field_len)
2290     {
2291       int data_bits_left = data_bits_len - bits_counter;
2292       obj->field_data[i].set_field_len = data_bits_left;
2293     }
2294   else
2295     obj->field_data[i].set_field_len = obj->field_data[i].max_field_len;
2296 
2297   obj->errnum = FIID_ERR_SUCCESS;
2298   return (data_len);
2299 }
2300 
2301 int
fiid_obj_get_all(fiid_obj_t obj,void * data,unsigned int data_len)2302 fiid_obj_get_all (fiid_obj_t obj,
2303                   void *data,
2304                   unsigned int data_len)
2305 {
2306   unsigned int bytes_len;
2307   int bits_len;
2308 
2309   if (!obj || obj->magic != FIID_OBJ_MAGIC)
2310     return (-1);
2311 
2312   if (!data)
2313     {
2314       obj->errnum = FIID_ERR_PARAMETERS;
2315       return (-1);
2316     }
2317 
2318   if ((bits_len = fiid_obj_len (obj)) < 0)
2319     return (-1);
2320 
2321   if (bits_len == (obj->data_len * 8))
2322     bytes_len = obj->data_len;
2323   else
2324     bytes_len = BITS_ROUND_BYTES (bits_len);
2325 
2326   if (data_len < bytes_len)
2327     {
2328       obj->errnum = FIID_ERR_OVERFLOW;
2329       return (-1);
2330     }
2331 
2332   if (bytes_len == obj->data_len)
2333     memcpy (data, obj->data, bytes_len);
2334   else
2335     {
2336       unsigned int bytes_written = 0, max_bits_counter = 0, set_bits_counter = 0,
2337         optional_bits_counter = 0, data_index = 0, obj_data_index = 0;
2338       unsigned int i;
2339 
2340       /* integer overflow conditions checked during object creation */
2341       for (i = 0; i < obj->field_data_len; i++)
2342         {
2343           unsigned int max_field_len = obj->field_data[i].max_field_len;
2344           unsigned int set_field_len = obj->field_data[i].set_field_len;
2345 
2346           max_bits_counter += max_field_len;
2347 
2348           if (set_field_len)
2349             {
2350               if (optional_bits_counter)
2351                 {
2352                   obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2353                   goto cleanup;
2354                 }
2355 
2356               if (set_field_len != max_field_len)
2357                 {
2358                   /* If there is an optional or variable length
2359                    * field, it cannot have only partial data.
2360                    */
2361                   if ((set_bits_counter + set_field_len) % 8)
2362                     {
2363                       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2364                       goto cleanup;
2365                     }
2366                 }
2367 
2368               set_bits_counter += set_field_len;
2369               if (!(set_bits_counter % 8))
2370                 {
2371                   unsigned int max_bytes_count = BITS_ROUND_BYTES (max_bits_counter);
2372                   unsigned int set_bytes_count = BITS_ROUND_BYTES (set_bits_counter);
2373 
2374                   memcpy (data + data_index,
2375                           obj->data + obj_data_index,
2376                           set_bytes_count);
2377 
2378                   bytes_written += set_bytes_count;
2379                   data_index += set_bytes_count;
2380                   obj_data_index += max_bytes_count;
2381                   set_bits_counter = 0;
2382                   max_bits_counter = 0;
2383                 }
2384             }
2385           else
2386             {
2387               /* All information must be collected in byte sized
2388                * chunks
2389                */
2390               if (set_bits_counter)
2391                 {
2392                   obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2393                   goto cleanup;
2394                 }
2395 
2396               /* Likewise, optional data should be aligned across
2397                * bytes
2398                */
2399               optional_bits_counter += max_field_len;
2400               if (optional_bits_counter && !(optional_bits_counter % 8))
2401                 {
2402                   /* an "assert" */
2403                   if (optional_bits_counter != max_bits_counter)
2404                     {
2405                       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2406                       goto cleanup;
2407                     }
2408 
2409                   obj_data_index += BITS_ROUND_BYTES (optional_bits_counter);
2410                   optional_bits_counter = 0;
2411                   max_bits_counter = 0;
2412                 }
2413             }
2414         }
2415 
2416       /* There shouldn't be anything left over */
2417       if (set_bits_counter)
2418         {
2419           obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2420           goto cleanup;
2421         }
2422 
2423       if (bytes_written != bytes_len)
2424         {
2425           obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2426           goto cleanup;
2427         }
2428     }
2429 
2430   obj->errnum = FIID_ERR_SUCCESS;
2431   return (bytes_len);
2432 
2433  cleanup:
2434   return (-1);
2435 }
2436 
2437 static int
_fiid_obj_max_block_len(fiid_obj_t obj,const char * field_start,const char * field_end)2438 _fiid_obj_max_block_len (fiid_obj_t obj,
2439                          const char *field_start,
2440                          const char *field_end)
2441 {
2442   int end;
2443   int start;
2444 
2445   assert (obj);
2446   assert (obj->magic == FIID_OBJ_MAGIC);
2447   assert (field_start);
2448   assert (field_end);
2449 
2450   if ((start = _fiid_obj_field_start (obj, field_start)) < 0)
2451     return (-1);
2452 
2453   if ((end = _fiid_obj_field_end (obj, field_end)) < 0)
2454     return (-1);
2455 
2456   if (start > end)
2457     {
2458       obj->errnum = FIID_ERR_PARAMETERS;
2459       return (-1);
2460     }
2461 
2462   return (end - start);
2463 }
2464 
2465 int
fiid_obj_set_block(fiid_obj_t obj,const char * field_start,const char * field_end,const void * data,unsigned int data_len)2466 fiid_obj_set_block (fiid_obj_t obj,
2467                     const char *field_start,
2468                     const char *field_end,
2469                     const void *data,
2470                     unsigned int data_len)
2471 {
2472   int block_bits_start, block_bits_len;
2473   unsigned int key_index_start, key_index_end;
2474   unsigned int block_bytes_len, bits_counter, data_bits_len, field_offset;
2475   unsigned int i;
2476 
2477   if (!obj || obj->magic != FIID_OBJ_MAGIC)
2478     return (-1);
2479 
2480   if (!field_start || !field_end || !data)
2481     {
2482       obj->errnum = FIID_ERR_PARAMETERS;
2483       return (-1);
2484     }
2485 
2486   if (_fiid_obj_lookup_field_index (obj, field_start, &key_index_start) < 0)
2487     return (-1);
2488 
2489   if (_fiid_obj_lookup_field_index (obj, field_end, &key_index_end) < 0)
2490     return (-1);
2491 
2492   if (key_index_start > key_index_end)
2493     {
2494       obj->errnum = FIID_ERR_PARAMETERS;
2495       return (-1);
2496     }
2497 
2498   /* achu: We assume the field must start on a byte boundary and end
2499    * on a byte boundary.
2500    */
2501 
2502   if ((block_bits_start = _fiid_obj_field_start (obj, field_start)) < 0)
2503     return (-1);
2504 
2505   if (block_bits_start % 8)
2506     {
2507       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2508       return (-1);
2509     }
2510 
2511   if ((block_bits_len = _fiid_obj_max_block_len (obj,
2512                                                  field_start,
2513                                                  field_end)) < 0)
2514     return (-1);
2515 
2516   if (block_bits_len % 8)
2517     {
2518       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2519       return (-1);
2520     }
2521 
2522   block_bytes_len = BITS_ROUND_BYTES (block_bits_len);
2523 
2524   if (data_len > block_bytes_len)
2525     data_len = block_bytes_len;
2526 
2527   /* achu: Potentially adjust index of last field */
2528   /* integer overflow conditions checked during object creation */
2529   data_bits_len = data_len * 8;
2530   if (data_len < block_bits_len)
2531     {
2532       bits_counter = 0;
2533 
2534       for (i = key_index_start; i <= key_index_end; i++)
2535         {
2536           bits_counter += obj->field_data[i].max_field_len;
2537           if (bits_counter >= data_bits_len)
2538             {
2539               /* achu: We assume the data must end on a byte boundary. */
2540               if (bits_counter % 8)
2541                 {
2542                   obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2543                   return (-1);
2544                 }
2545               else
2546                 break;
2547             }
2548 
2549         }
2550       key_index_end = i;
2551     }
2552 
2553   field_offset = BITS_ROUND_BYTES (block_bits_start);
2554   memcpy ((obj->data + field_offset), data, data_len);
2555 
2556   /* integer overflow conditions checked during object creation */
2557   bits_counter = 0;
2558   for (i = key_index_start; i < key_index_end; i++)
2559     {
2560       obj->field_data[i].set_field_len = obj->field_data[i].max_field_len;
2561       bits_counter += obj->field_data[i].set_field_len;
2562     }
2563   if (data_bits_len < bits_counter + obj->field_data[key_index_end].max_field_len)
2564     {
2565       int data_bits_left = data_bits_len - bits_counter;
2566       obj->field_data[i].set_field_len = data_bits_left;
2567     }
2568   else
2569     obj->field_data[i].set_field_len = obj->field_data[i].max_field_len;
2570 
2571   obj->errnum = FIID_ERR_SUCCESS;
2572   return (data_len);
2573 }
2574 
2575 int
fiid_obj_get_block(fiid_obj_t obj,const char * field_start,const char * field_end,void * data,unsigned int data_len)2576 fiid_obj_get_block (fiid_obj_t obj,
2577                     const char *field_start,
2578                     const char *field_end,
2579                     void *data,
2580                     unsigned int data_len)
2581 {
2582   int block_bits_start, block_bits_max_len, block_bits_set_len;
2583   unsigned int block_bytes_max_len, block_bytes_set_len, field_offset;
2584   unsigned int key_index_start, key_index_end;
2585 
2586   if (!obj || obj->magic != FIID_OBJ_MAGIC)
2587     return (-1);
2588 
2589   if (!field_start || !field_end || !data)
2590     {
2591       obj->errnum = FIID_ERR_PARAMETERS;
2592       return (-1);
2593     }
2594 
2595   if (_fiid_obj_lookup_field_index (obj, field_start, &key_index_start) < 0)
2596     return (-1);
2597 
2598   if (_fiid_obj_lookup_field_index (obj, field_end, &key_index_end) < 0)
2599     return (-1);
2600 
2601   if (key_index_start > key_index_end)
2602     {
2603       obj->errnum = FIID_ERR_PARAMETERS;
2604       return (-1);
2605     }
2606 
2607   /* achu: We assume the field must start on a byte boundary and ends
2608    * on a byte boundary.
2609    */
2610 
2611   if ((block_bits_start = _fiid_obj_field_start (obj, field_start)) < 0)
2612     return (-1);
2613 
2614   if (block_bits_start % 8)
2615     {
2616       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2617       return (-1);
2618     }
2619 
2620   if ((block_bits_max_len = _fiid_obj_max_block_len (obj, field_start, field_end)) < 0)
2621     return (-1);
2622 
2623   if (block_bits_max_len % 8)
2624     {
2625       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2626       return (-1);
2627     }
2628 
2629   if ((block_bits_set_len = fiid_obj_block_len (obj, field_start, field_end)) < 0)
2630     return (-1);
2631 
2632   if (block_bits_set_len % 8)
2633     {
2634       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2635       return (-1);
2636     }
2637 
2638   block_bytes_max_len = BITS_ROUND_BYTES (block_bits_max_len);
2639   block_bytes_set_len = BITS_ROUND_BYTES (block_bits_set_len);
2640 
2641   if (data_len < block_bytes_set_len)
2642     {
2643       obj->errnum = FIID_ERR_OVERFLOW;
2644       return (-1);
2645     }
2646 
2647   field_offset = BITS_ROUND_BYTES (block_bits_start);
2648 
2649   memset (data, '\0', data_len);
2650 
2651   if (block_bytes_set_len == block_bytes_max_len)
2652     memcpy (data, (obj->data + field_offset), block_bytes_set_len);
2653   else
2654     {
2655       unsigned int bytes_written = 0, max_bits_counter = 0, set_bits_counter = 0,
2656         optional_bits_counter = 0, data_index = 0, obj_data_index = field_offset;
2657       unsigned int i;
2658 
2659       /* integer overflow conditions checked during object creation */
2660       for (i = key_index_start; i <= key_index_end; i++)
2661         {
2662           unsigned int max_field_len = obj->field_data[i].max_field_len;
2663           unsigned int set_field_len = obj->field_data[i].set_field_len;
2664 
2665           max_bits_counter += max_field_len;
2666 
2667           if (set_field_len)
2668             {
2669               if (optional_bits_counter)
2670                 {
2671                   obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2672                   goto cleanup;
2673                 }
2674 
2675               if (set_field_len != max_field_len)
2676                 {
2677                   /* If there is an optional or variable length
2678                    * field, it cannot have only partial data.
2679                    */
2680                   if ((set_bits_counter + set_field_len) % 8)
2681                     {
2682                       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2683                       goto cleanup;
2684                     }
2685                 }
2686 
2687               set_bits_counter += set_field_len;
2688               if (!(set_bits_counter % 8))
2689                 {
2690                   unsigned int max_bytes_count = BITS_ROUND_BYTES (max_bits_counter);
2691                   unsigned int set_bytes_count = BITS_ROUND_BYTES (set_bits_counter);
2692 
2693                   memcpy (data + data_index,
2694                           obj->data + obj_data_index,
2695                           set_bytes_count);
2696 
2697                   bytes_written += set_bytes_count;
2698                   data_index += set_bytes_count;
2699                   obj_data_index += max_bytes_count;
2700                   set_bits_counter = 0;
2701                   max_bits_counter = 0;
2702                 }
2703             }
2704           else
2705             {
2706               /* All information must be collected in byte sized
2707                * chunks
2708                */
2709               if (set_bits_counter)
2710                 {
2711                   obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2712                   goto cleanup;
2713                 }
2714 
2715               /* Likewise, optional data should be aligned across
2716                * bytes
2717                */
2718               optional_bits_counter += max_field_len;
2719               if (optional_bits_counter && !(optional_bits_counter % 8))
2720                 {
2721                   /* an "assert" */
2722                   if (optional_bits_counter != max_bits_counter)
2723                     {
2724                       obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2725                       goto cleanup;
2726                     }
2727 
2728                   obj_data_index += BITS_ROUND_BYTES (optional_bits_counter);
2729                   optional_bits_counter = 0;
2730                   max_bits_counter = 0;
2731                 }
2732             }
2733 
2734         }
2735 
2736       /* There shouldn't be anything left over */
2737       if (set_bits_counter)
2738         {
2739           obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2740           goto cleanup;
2741         }
2742 
2743       if (bytes_written != block_bytes_set_len)
2744         {
2745           obj->errnum = FIID_ERR_DATA_NOT_BYTE_ALIGNED;
2746           goto cleanup;
2747         }
2748     }
2749 
2750   obj->errnum = FIID_ERR_SUCCESS;
2751   return (block_bytes_set_len);
2752 
2753  cleanup:
2754   if (data)
2755     memset (data, '\0', data_len);
2756   return (-1);
2757 }
2758 
2759 fiid_iterator_t
fiid_iterator_create(fiid_obj_t obj)2760 fiid_iterator_create (fiid_obj_t obj)
2761 {
2762   fiid_iterator_t iter = NULL;
2763 
2764   if (!obj || obj->magic != FIID_OBJ_MAGIC)
2765     goto cleanup;
2766 
2767   if (!(iter = (fiid_iterator_t)malloc (sizeof (struct fiid_iterator))))
2768     {
2769       obj->errnum = FIID_ERR_OUT_OF_MEMORY;
2770       goto cleanup;
2771     }
2772   memset (iter, '\0', sizeof (struct fiid_iterator));
2773   iter->magic = FIID_ITERATOR_MAGIC;
2774   iter->current_index = 0;
2775 
2776   /* The - 1 below is because field_data_len is length of the array.
2777    * The iterator is concerned about array indexes.
2778    */
2779   iter->last_index = obj->field_data_len - 1;
2780 
2781   if (!(iter->obj = fiid_obj_dup (obj)))
2782     goto cleanup;
2783 
2784   obj->errnum = FIID_ERR_SUCCESS;
2785   return (iter);
2786 
2787  cleanup:
2788   if (iter)
2789     {
2790       if (iter->obj)
2791         fiid_obj_destroy (iter->obj);
2792       free (iter);
2793     }
2794 
2795   return (NULL);
2796 }
2797 
2798 void
fiid_iterator_destroy(fiid_iterator_t iter)2799 fiid_iterator_destroy (fiid_iterator_t iter)
2800 {
2801   if (!(iter && iter->magic == FIID_ITERATOR_MAGIC))
2802     return;
2803 
2804   iter->magic = ~FIID_ITERATOR_MAGIC;
2805   iter->errnum = FIID_ERR_SUCCESS;
2806   fiid_obj_destroy (iter->obj);
2807   free (iter);
2808 }
2809 
2810 fiid_err_t
fiid_iterator_errnum(fiid_iterator_t iter)2811 fiid_iterator_errnum (fiid_iterator_t iter)
2812 {
2813   if (!iter)
2814     return (FIID_ERR_ITERATOR_NULL);
2815   else if (iter->magic != FIID_ITERATOR_MAGIC)
2816     return (FIID_ERR_ITERATOR_INVALID);
2817   else
2818     return (iter->errnum);
2819 }
2820 
2821 char *
fiid_iterator_errormsg(fiid_iterator_t iter)2822 fiid_iterator_errormsg (fiid_iterator_t iter)
2823 {
2824   return (fiid_strerror (fiid_iterator_errnum (iter)));
2825 }
2826 
2827 int
fiid_iterator_reset(fiid_iterator_t iter)2828 fiid_iterator_reset (fiid_iterator_t iter)
2829 {
2830   if (!(iter && iter->magic == FIID_ITERATOR_MAGIC))
2831     return (-1);
2832 
2833   iter->current_index = 0;
2834   iter->errnum = FIID_ERR_SUCCESS;
2835   return (0);
2836 }
2837 
2838 int
fiid_iterator_next(fiid_iterator_t iter)2839 fiid_iterator_next (fiid_iterator_t iter)
2840 {
2841   if (!(iter && iter->magic == FIID_ITERATOR_MAGIC))
2842     return (-1);
2843 
2844   if (iter->current_index != iter->last_index)
2845     iter->current_index++;
2846 
2847   iter->errnum = FIID_ERR_SUCCESS;
2848   return (0);
2849 }
2850 
2851 int
fiid_iterator_end(fiid_iterator_t iter)2852 fiid_iterator_end (fiid_iterator_t iter)
2853 {
2854   if (!(iter && iter->magic == FIID_ITERATOR_MAGIC))
2855     return (-1);
2856 
2857   iter->errnum = FIID_ERR_SUCCESS;
2858   return ((iter->current_index == iter->last_index) ? 1 : 0);
2859 }
2860 
2861 int
fiid_iterator_field_len(fiid_iterator_t iter)2862 fiid_iterator_field_len (fiid_iterator_t iter)
2863 {
2864   if (!(iter && iter->magic == FIID_ITERATOR_MAGIC))
2865     return (-1);
2866 
2867   iter->errnum = FIID_ERR_SUCCESS;
2868   /* integer overflow conditions checked during object creation */
2869   return (iter->obj->field_data[iter->current_index].set_field_len);
2870 }
2871 
2872 char *
fiid_iterator_key(fiid_iterator_t iter)2873 fiid_iterator_key (fiid_iterator_t iter)
2874 {
2875   if (!(iter && iter->magic == FIID_ITERATOR_MAGIC))
2876     return (NULL);
2877 
2878   iter->errnum = FIID_ERR_SUCCESS;
2879   return (iter->obj->field_data[iter->current_index].key);
2880 }
2881 
2882 int
fiid_iterator_get(fiid_iterator_t iter,uint64_t * val)2883 fiid_iterator_get (fiid_iterator_t iter, uint64_t *val)
2884 {
2885   char *key;
2886   int rv;
2887 
2888   if (!(iter && iter->magic == FIID_ITERATOR_MAGIC))
2889     return (-1);
2890 
2891   key = iter->obj->field_data[iter->current_index].key;
2892   rv = fiid_obj_get (iter->obj, key, val);
2893   iter->errnum = (iter->obj->errnum);
2894   return (rv);
2895 }
2896 
2897 int
fiid_iterator_get_data(fiid_iterator_t iter,void * data,unsigned int data_len)2898 fiid_iterator_get_data (fiid_iterator_t iter,
2899                         void *data,
2900                         unsigned int data_len)
2901 {
2902   char *key;
2903   int rv;
2904 
2905   if (!(iter && iter->magic == FIID_ITERATOR_MAGIC))
2906     return (-1);
2907 
2908   key = iter->obj->field_data[iter->current_index].key;
2909   rv = fiid_obj_get_data (iter->obj, key, data, data_len);
2910   iter->errnum = (iter->obj->errnum);
2911   return (rv);
2912 }
2913