1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <util.h>
4 
5 #include "sd-bus.h"
6 
7 #include "bus-signature.h"
8 #include "bus-type.h"
9 
signature_element_length_internal(const char * s,bool allow_dict_entry,unsigned array_depth,unsigned struct_depth,size_t * l)10 static int signature_element_length_internal(
11                 const char *s,
12                 bool allow_dict_entry,
13                 unsigned array_depth,
14                 unsigned struct_depth,
15                 size_t *l) {
16 
17         int r;
18 
19         if (!s)
20                 return -EINVAL;
21 
22         assert(l);
23 
24         if (bus_type_is_basic(*s) || *s == SD_BUS_TYPE_VARIANT) {
25                 *l = 1;
26                 return 0;
27         }
28 
29         if (*s == SD_BUS_TYPE_ARRAY) {
30                 size_t t;
31 
32                 if (array_depth >= 32)
33                         return -EINVAL;
34 
35                 r = signature_element_length_internal(s + 1, true, array_depth+1, struct_depth, &t);
36                 if (r < 0)
37                         return r;
38 
39                 *l = t + 1;
40                 return 0;
41         }
42 
43         if (*s == SD_BUS_TYPE_STRUCT_BEGIN) {
44                 const char *p = s + 1;
45 
46                 if (struct_depth >= 32)
47                         return -EINVAL;
48 
49                 while (*p != SD_BUS_TYPE_STRUCT_END) {
50                         size_t t;
51 
52                         r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t);
53                         if (r < 0)
54                                 return r;
55 
56                         p += t;
57                 }
58 
59                 if (p - s < 2)
60                         /* D-Bus spec: Empty structures are not allowed; there
61                          * must be at least one type code between the parentheses.
62                          */
63                         return -EINVAL;
64 
65                 *l = p - s + 1;
66                 return 0;
67         }
68 
69         if (*s == SD_BUS_TYPE_DICT_ENTRY_BEGIN && allow_dict_entry) {
70                 const char *p = s + 1;
71                 unsigned n = 0;
72 
73                 if (struct_depth >= 32)
74                         return -EINVAL;
75 
76                 while (*p != SD_BUS_TYPE_DICT_ENTRY_END) {
77                         size_t t;
78 
79                         if (n == 0 && !bus_type_is_basic(*p))
80                                 return -EINVAL;
81 
82                         r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t);
83                         if (r < 0)
84                                 return r;
85 
86                         p += t;
87                         n++;
88                 }
89 
90                 if (n != 2)
91                         return -EINVAL;
92 
93                 *l = p - s + 1;
94                 return 0;
95         }
96 
97         return -EINVAL;
98 }
99 
signature_element_length(const char * s,size_t * l)100 int signature_element_length(const char *s, size_t *l) {
101         return signature_element_length_internal(s, true, 0, 0, l);
102 }
103 
signature_is_single(const char * s,bool allow_dict_entry)104 bool signature_is_single(const char *s, bool allow_dict_entry) {
105         int r;
106         size_t t;
107 
108         if (!s)
109                 return false;
110 
111         r = signature_element_length_internal(s, allow_dict_entry, 0, 0, &t);
112         if (r < 0)
113                 return false;
114 
115         return s[t] == 0;
116 }
117 
signature_is_pair(const char * s)118 bool signature_is_pair(const char *s) {
119 
120         if (!s)
121                 return false;
122 
123         if (!bus_type_is_basic(*s))
124                 return false;
125 
126         return signature_is_single(s + 1, false);
127 }
128 
signature_is_valid(const char * s,bool allow_dict_entry)129 bool signature_is_valid(const char *s, bool allow_dict_entry) {
130         const char *p;
131         int r;
132 
133         if (!s)
134                 return false;
135 
136         p = s;
137         while (*p) {
138                 size_t t;
139 
140                 r = signature_element_length_internal(p, allow_dict_entry, 0, 0, &t);
141                 if (r < 0)
142                         return false;
143 
144                 p += t;
145         }
146 
147         return p - s <= SD_BUS_MAXIMUM_SIGNATURE_LENGTH;
148 }
149