1 /*
2 Copyright 2021 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25 #include <exec-config.h>
26
27 #include <alloc.h>
28 #include <string_lib.h>
29 #include <writer.h>
30
31 #include <rlist.h>
32 #include <eval_context.h>
33 #include <conversion.h>
34 #include <generic_agent.h> // TODO: fix
35 #include <regex.h> // pcre_free()
36 #include <item_lib.h>
37
38
GetIpAddresses(const EvalContext * ctx)39 static char *GetIpAddresses(const EvalContext *ctx)
40 {
41 Writer *ipbuf = StringWriter();
42
43 for (Item *iptr = EvalContextGetIpAddresses(ctx); iptr != NULL; iptr = iptr->next)
44 {
45 WriterWrite(ipbuf, iptr->name);
46 if (iptr->next != NULL)
47 {
48 WriterWriteChar(ipbuf, ' ');
49 }
50 }
51
52 return StringWriterClose(ipbuf);
53 }
54
RegexFree(void * ptr)55 static void RegexFree(void *ptr)
56 {
57 pcre_free(ptr);
58 }
59
MailFilterFill(const char * str,Seq ** output,Seq ** output_regex,const char * filter_type)60 static void MailFilterFill(const char *str,
61 Seq **output, Seq **output_regex,
62 const char *filter_type)
63 {
64 const char *errorstr;
65 int erroffset;
66 pcre *rx = pcre_compile(str,
67 PCRE_MULTILINE | PCRE_DOTALL | PCRE_ANCHORED,
68 &errorstr, &erroffset, NULL);
69 if (!rx)
70 {
71 Log(LOG_LEVEL_ERR,
72 "Invalid regular expression in mailfilter_%s: "
73 "pcre_compile() '%s' in expression '%s' (offset: %d). "
74 "Ignoring expression.", filter_type,
75 errorstr, str, erroffset);
76 }
77 else
78 {
79 SeqAppend(*output, xstrdup(str));
80 SeqAppend(*output_regex, rx);
81 }
82 }
83
RlistMailFilterFill(const Rlist * input,Seq ** output,Seq ** output_regex,const char * filter_type)84 static void RlistMailFilterFill(const Rlist *input,
85 Seq **output, Seq **output_regex,
86 const char *filter_type)
87 {
88 int len = RlistLen(input);
89
90 *output = SeqNew(len, &free);
91 *output_regex = SeqNew(len, &RegexFree);
92
93 const Rlist *ptr = input;
94 for (int i = 0; i < len; i++)
95 {
96 const char *str = ptr->val.item;
97 MailFilterFill(str, output, output_regex, filter_type);
98
99 ptr = ptr->next;
100 }
101 }
102
SeqMailFilterFill(const Seq * input,Seq ** output,Seq ** output_regex,const char * filter_type)103 static void SeqMailFilterFill(const Seq *input,
104 Seq **output, Seq **output_regex,
105 const char *filter_type)
106 {
107 int len = SeqLength(input);
108
109 *output = SeqNew(len, &free);
110 *output_regex = SeqNew(len, &RegexFree);
111
112 for (int i = 0; i < len; i++)
113 {
114 MailFilterFill(SeqAt(input, i), output, output_regex, filter_type);
115 }
116 }
117
ExecConfigNew(bool scheduled_run,const EvalContext * ctx,const Policy * policy)118 ExecConfig *ExecConfigNew(bool scheduled_run, const EvalContext *ctx, const Policy *policy)
119 {
120 ExecConfig *exec_config = xcalloc(1, sizeof(ExecConfig));
121
122 exec_config->scheduled_run = scheduled_run;
123 exec_config->exec_command = xstrdup("");
124 exec_config->agent_expireafter = 2 * 60; /* two hours */
125
126 exec_config->mail_server = xstrdup("");
127 exec_config->mail_from_address = xstrdup("");
128 exec_config->mail_to_address = xstrdup("");
129 exec_config->mail_subject = xstrdup("");
130 exec_config->mail_max_lines = 30;
131 exec_config->mailfilter_include = SeqNew(0, &free);
132 exec_config->mailfilter_include_regex = SeqNew(0, &RegexFree);
133 exec_config->mailfilter_exclude = SeqNew(0, &free);
134 exec_config->mailfilter_exclude_regex = SeqNew(0, &RegexFree);
135
136 exec_config->fq_name = xstrdup(VFQNAME);
137 exec_config->ip_address = xstrdup(VIPADDRESS);
138 exec_config->ip_addresses = GetIpAddresses(ctx);
139
140 Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_EXECUTOR);
141 if (constraints)
142 {
143 for (size_t i = 0; i < SeqLength(constraints); i++)
144 {
145 Constraint *cp = SeqAt(constraints, i);
146
147 if (!IsDefinedClass(ctx, cp->classes))
148 {
149 continue;
150 }
151
152 VarRef *ref = VarRefParseFromScope(cp->lval, "control_executor");
153 DataType t;
154 const void *value = EvalContextVariableGet(ctx, ref, &t);
155 VarRefDestroy(ref);
156
157 if (t == CF_DATA_TYPE_NONE)
158 {
159 ProgrammingError("Unknown attribute '%s' in control body,"
160 " should have already been stopped by the parser",
161 cp->lval);
162 }
163
164 if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILFROM].lval) == 0)
165 {
166 free(exec_config->mail_from_address);
167 exec_config->mail_from_address = xstrdup(value);
168 Log(LOG_LEVEL_DEBUG, "mailfrom '%s'", exec_config->mail_from_address);
169 }
170 else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILTO].lval) == 0)
171 {
172 free(exec_config->mail_to_address);
173 exec_config->mail_to_address = xstrdup(value);
174 Log(LOG_LEVEL_DEBUG, "mailto '%s'", exec_config->mail_to_address);
175 }
176 else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILSUBJECT].lval) == 0)
177 {
178 free(exec_config->mail_subject);
179 exec_config->mail_subject = xstrdup(value);
180 Log(LOG_LEVEL_DEBUG, "mailsubject '%s'", exec_config->mail_subject);
181 }
182 else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_SMTPSERVER].lval) == 0)
183 {
184 free(exec_config->mail_server);
185 exec_config->mail_server = xstrdup(value);
186 Log(LOG_LEVEL_DEBUG, "smtpserver '%s'", exec_config->mail_server);
187 }
188 else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_EXECCOMMAND].lval) == 0)
189 {
190 free(exec_config->exec_command);
191 exec_config->exec_command = xstrdup(value);
192 Log(LOG_LEVEL_DEBUG, "exec_command '%s'", exec_config->exec_command);
193 }
194 else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_AGENT_EXPIREAFTER].lval) == 0)
195 {
196 exec_config->agent_expireafter = IntFromString(value);
197 Log(LOG_LEVEL_DEBUG, "agent_expireafter %d", exec_config->agent_expireafter);
198 }
199 else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILMAXLINES].lval) == 0)
200 {
201 exec_config->mail_max_lines = IntFromString(value);
202 Log(LOG_LEVEL_DEBUG, "maxlines %d", exec_config->mail_max_lines);
203 }
204 else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILFILTER_INCLUDE].lval) == 0)
205 {
206 SeqDestroy(exec_config->mailfilter_include);
207 SeqDestroy(exec_config->mailfilter_include_regex);
208 RlistMailFilterFill(value, &exec_config->mailfilter_include,
209 &exec_config->mailfilter_include_regex, "include");
210 }
211 else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILFILTER_EXCLUDE].lval) == 0)
212 {
213 SeqDestroy(exec_config->mailfilter_exclude);
214 SeqDestroy(exec_config->mailfilter_exclude_regex);
215 RlistMailFilterFill(value, &exec_config->mailfilter_exclude,
216 &exec_config->mailfilter_exclude_regex, "exclude");
217 }
218 }
219 }
220
221 return exec_config;
222 }
223
ExecConfigCopy(const ExecConfig * config)224 ExecConfig *ExecConfigCopy(const ExecConfig *config)
225 {
226 ExecConfig *copy = xcalloc(1, sizeof(ExecConfig));
227
228 copy->scheduled_run = config->scheduled_run;
229 copy->exec_command = xstrdup(config->exec_command);
230 copy->agent_expireafter = config->agent_expireafter;
231 copy->mail_server = xstrdup(config->mail_server);
232 copy->mail_from_address = xstrdup(config->mail_from_address);
233 copy->mail_to_address = xstrdup(config->mail_to_address);
234 copy->mail_subject = xstrdup(config->mail_subject);
235 copy->mail_max_lines = config->mail_max_lines;
236 SeqMailFilterFill(config->mailfilter_include, ©->mailfilter_include,
237 ©->mailfilter_include_regex, "include");
238 SeqMailFilterFill(config->mailfilter_exclude, ©->mailfilter_exclude,
239 ©->mailfilter_exclude_regex, "exclude");
240 copy->fq_name = xstrdup(config->fq_name);
241 copy->ip_address = xstrdup(config->ip_address);
242 copy->ip_addresses = xstrdup(config->ip_addresses);
243
244 return copy;
245 }
246
ExecConfigDestroy(ExecConfig * exec_config)247 void ExecConfigDestroy(ExecConfig *exec_config)
248 {
249 if (exec_config)
250 {
251 free(exec_config->exec_command);
252 free(exec_config->mail_server);
253 free(exec_config->mail_from_address);
254 free(exec_config->mail_to_address);
255 free(exec_config->mail_subject);
256 SeqDestroy(exec_config->mailfilter_include);
257 SeqDestroy(exec_config->mailfilter_exclude);
258 SeqDestroy(exec_config->mailfilter_include_regex);
259 SeqDestroy(exec_config->mailfilter_exclude_regex);
260 free(exec_config->fq_name);
261 free(exec_config->ip_address);
262 free(exec_config->ip_addresses);
263
264 free(exec_config);
265 }
266 }
267