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