1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "af-list.h"
4 #include "extract-word.h"
5 #include "ip-protocol-list.h"
6 #include "log.h"
7 #include "parse-helpers.h"
8 #include "parse-util.h"
9 #include "path-util.h"
10 #include "utf8.h"
11
path_simplify_and_warn(char * path,unsigned flag,const char * unit,const char * filename,unsigned line,const char * lvalue)12 int path_simplify_and_warn(
13 char *path,
14 unsigned flag,
15 const char *unit,
16 const char *filename,
17 unsigned line,
18 const char *lvalue) {
19
20 bool fatal = flag & PATH_CHECK_FATAL;
21
22 assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
23
24 if (!utf8_is_valid(path))
25 return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
26
27 if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
28 bool absolute;
29
30 absolute = path_is_absolute(path);
31
32 if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
33 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
34 "%s= path is not absolute%s: %s",
35 lvalue, fatal ? "" : ", ignoring", path);
36
37 if (absolute && (flag & PATH_CHECK_RELATIVE))
38 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
39 "%s= path is absolute%s: %s",
40 lvalue, fatal ? "" : ", ignoring", path);
41 }
42
43 path_simplify(path);
44
45 if (!path_is_valid(path))
46 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
47 "%s= path has invalid length (%zu bytes)%s.",
48 lvalue, strlen(path), fatal ? "" : ", ignoring");
49
50 if (!path_is_normalized(path))
51 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
52 "%s= path is not normalized%s: %s",
53 lvalue, fatal ? "" : ", ignoring", path);
54
55 return 0;
56 }
57
parse_af_token(const char * token,int * family,int * ip_protocol,uint16_t * nr_ports,uint16_t * port_min)58 static int parse_af_token(
59 const char *token,
60 int *family,
61 int *ip_protocol,
62 uint16_t *nr_ports,
63 uint16_t *port_min) {
64
65 int af;
66
67 assert(token);
68 assert(family);
69
70 af = af_from_ipv4_ipv6(token);
71 if (af == AF_UNSPEC)
72 return -EINVAL;
73
74 *family = af;
75 return 0;
76 }
77
parse_ip_protocol_token(const char * token,int * family,int * ip_protocol,uint16_t * nr_ports,uint16_t * port_min)78 static int parse_ip_protocol_token(
79 const char *token,
80 int *family,
81 int *ip_protocol,
82 uint16_t *nr_ports,
83 uint16_t *port_min) {
84
85 int proto;
86
87 assert(token);
88 assert(ip_protocol);
89
90 proto = ip_protocol_from_tcp_udp(token);
91 if (proto < 0)
92 return -EINVAL;
93
94 *ip_protocol = proto;
95 return 0;
96 }
97
parse_ip_ports_token(const char * token,int * family,int * ip_protocol,uint16_t * nr_ports,uint16_t * port_min)98 static int parse_ip_ports_token(
99 const char *token,
100 int *family,
101 int *ip_protocol,
102 uint16_t *nr_ports,
103 uint16_t *port_min) {
104
105 assert(token);
106 assert(nr_ports);
107 assert(port_min);
108
109 if (streq(token, "any"))
110 *nr_ports = *port_min = 0;
111 else {
112 uint16_t mn = 0, mx = 0;
113 int r = parse_ip_port_range(token, &mn, &mx);
114 if (r < 0)
115 return r;
116
117 *nr_ports = mx - mn + 1;
118 *port_min = mn;
119 }
120
121 return 0;
122 }
123
124 typedef int (*parse_token_f)(
125 const char *,
126 int *,
127 int *,
128 uint16_t *,
129 uint16_t *);
130
parse_socket_bind_item(const char * str,int * address_family,int * ip_protocol,uint16_t * nr_ports,uint16_t * port_min)131 int parse_socket_bind_item(
132 const char *str,
133 int *address_family,
134 int *ip_protocol,
135 uint16_t *nr_ports,
136 uint16_t *port_min) {
137
138 /* Order of token parsers is important. */
139 const parse_token_f parsers[] = {
140 &parse_af_token,
141 &parse_ip_protocol_token,
142 &parse_ip_ports_token,
143 };
144 parse_token_f const *parser_ptr = parsers;
145 int af = AF_UNSPEC, proto = 0, r;
146 uint16_t nr = 0, mn = 0;
147 const char *p = str;
148
149 assert(str);
150 assert(address_family);
151 assert(ip_protocol);
152 assert(nr_ports);
153 assert(port_min);
154
155 if (isempty(p))
156 return -EINVAL;
157
158 for (;;) {
159 _cleanup_free_ char *token = NULL;
160
161 r = extract_first_word(&p, &token, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
162 if (r == 0)
163 break;
164 if (r < 0)
165 return r;
166
167 if (isempty(token))
168 return -EINVAL;
169
170 while (parser_ptr != parsers + ELEMENTSOF(parsers)) {
171 r = (*parser_ptr)(token, &af, &proto, &nr, &mn);
172 if (r == -ENOMEM)
173 return r;
174
175 ++parser_ptr;
176 /* Continue to next token if parsing succeeded,
177 * otherwise apply next parser to the same token.
178 */
179 if (r >= 0)
180 break;
181 }
182 if (parser_ptr == parsers + ELEMENTSOF(parsers))
183 break;
184 }
185
186 /* Failed to parse a token. */
187 if (r < 0)
188 return r;
189
190 /* Parsers applied successfully, but end of the string not reached. */
191 if (p)
192 return -EINVAL;
193
194 *address_family = af;
195 *ip_protocol = proto;
196 *nr_ports = nr;
197 *port_min = mn;
198 return 0;
199 }
200