iptables: fix regression with unintended free in need_protomatch
[project/firewall3.git] / includes.c
1 /*
2 * firewall3 - 3rd OpenWrt UCI firewall implementation
3 *
4 * Copyright (C) 2013 Jo-Philipp Wich <jo@mein.io>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "includes.h"
20
21
22 const struct fw3_option fw3_include_opts[] = {
23 FW3_OPT("enabled", bool, include, enabled),
24
25 FW3_OPT("path", string, include, path),
26 FW3_OPT("type", include_type, include, type),
27 FW3_OPT("family", family, include, family),
28 FW3_OPT("reload", bool, include, reload),
29
30 { }
31 };
32
33 static bool
34 check_include(struct fw3_state *state, struct fw3_include *include, struct uci_element *e)
35 {
36 if (!include->enabled)
37 return false;
38
39 if (!include->path)
40 {
41 warn_section("include", include, e, "must specify a path");
42 return false;
43 }
44
45 if (include->type == FW3_INC_TYPE_RESTORE && !include->family)
46 warn_section("include", include, e, "does not specify a family, include will get"
47 "loaded with both iptables-restore and ip6tables-restore!");
48
49 return true;
50 }
51
52 static struct fw3_include *
53 fw3_alloc_include(struct fw3_state *state)
54 {
55 struct fw3_include *include;
56
57 include = calloc(1, sizeof(*include));
58 if (!include)
59 return NULL;
60
61 include->enabled = true;
62
63 list_add_tail(&include->list, &state->includes);
64
65 return include;
66 }
67
68 void
69 fw3_load_includes(struct fw3_state *state, struct uci_package *p,
70 struct blob_attr *a)
71 {
72 struct uci_section *s;
73 struct uci_element *e;
74 struct fw3_include *include;
75 struct blob_attr *entry;
76 unsigned rem;
77
78 INIT_LIST_HEAD(&state->includes);
79
80 blob_for_each_attr(entry, a, rem)
81 {
82 const char *type;
83 const char *name = "ubus include";
84
85 if (!fw3_attr_parse_name_type(entry, &name, &type))
86 continue;
87
88 if (strcmp(type, "script") && strcmp(type, "restore"))
89 continue;
90
91 include = fw3_alloc_include(state);
92 if (!include)
93 continue;
94
95 if (!fw3_parse_blob_options(include, fw3_include_opts, entry, name))
96 {
97 warn_section("include", include, NULL, "skipped due to invalid options");
98 fw3_free_include(include);
99 continue;
100 }
101
102 if (!check_include(state, include, NULL))
103 fw3_free_include(include);
104 }
105
106 uci_foreach_element(&p->sections, e)
107 {
108 s = uci_to_section(e);
109
110 if (strcmp(s->type, "include"))
111 continue;
112
113 include = fw3_alloc_include(state);
114 if (!include)
115 continue;
116
117 include->name = e->name;
118
119 if (!fw3_parse_options(include, fw3_include_opts, s))
120 warn_elem(e, "has invalid options");
121
122 if (!check_include(state, include, e))
123 fw3_free_include(include);
124 }
125 }
126
127
128 static void
129 print_include(struct fw3_include *include)
130 {
131 FILE *f;
132 char line[1024];
133
134 info(" * Loading include '%s'", include->path);
135
136 if (!(f = fopen(include->path, "r")))
137 {
138 info(" ! Skipping due to open error: %s", strerror(errno));
139 return;
140 }
141
142 while (fgets(line, sizeof(line), f))
143 fw3_pr(line);
144
145 fclose(f);
146 }
147
148 void
149 fw3_print_includes(struct fw3_state *state, enum fw3_family family, bool reload)
150 {
151 struct fw3_include *include;
152
153 bool exec = false;
154 const char *restore = "iptables-restore";
155
156 if (family == FW3_FAMILY_V6)
157 restore = "ip6tables-restore";
158
159 list_for_each_entry(include, &state->includes, list)
160 {
161 if (reload && !include->reload)
162 continue;
163
164 if (include->type != FW3_INC_TYPE_RESTORE)
165 continue;
166
167 if (!fw3_is_family(include, family))
168 continue;
169
170 if (!exec)
171 {
172 exec = fw3_command_pipe(false, restore, "--noflush");
173
174 if (!exec)
175 return;
176 }
177
178 print_include(include);
179 }
180
181 if (exec)
182 fw3_command_close();
183 }
184
185
186 static void
187 run_include(struct fw3_include *include)
188 {
189 int rv;
190 struct stat s;
191 const char *tmpl =
192 "config() { "
193 "echo \"You cannot use UCI in firewall includes!\" >&2; "
194 "exit 1; "
195 "}; . %s";
196
197 char buf[PATH_MAX + sizeof(tmpl)];
198
199 info(" * Running script '%s'", include->path);
200
201 if (stat(include->path, &s))
202 {
203 info(" ! Skipping due to path error: %s", strerror(errno));
204 return;
205 }
206
207 snprintf(buf, sizeof(buf), tmpl, include->path);
208 rv = system(buf);
209
210 if (rv)
211 info(" ! Failed with exit code %u", WEXITSTATUS(rv));
212 }
213
214 void
215 fw3_run_includes(struct fw3_state *state, bool reload)
216 {
217 struct fw3_include *include;
218
219 list_for_each_entry(include, &state->includes, list)
220 {
221 if (reload && !include->reload)
222 continue;
223
224 if (include->type == FW3_INC_TYPE_SCRIPT)
225 run_include(include);
226 }
227 }