1 /*
2  * Copyright (C) 2001-2003 FhG Fokus
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 
22 /*!
23  * \file
24  * \brief Exec module:: Module interface
25  * \ingroup exec
26  * Module: \ref exec
27  */
28 
29 /**
30  * @defgroup exec Execute external applications
31  * @brief Kamailio exec module
32  *
33  * The exec module allows external commands to be executed from a Kamailio script.
34  * The commands may be any valid shell commands--the command string is passed to the
35  * shell using “popen” command. Kamailio passes additional information about the request
36  * in environment variables.
37  *
38  */
39 
40 
41 #include <stdio.h>
42 #include <strings.h>
43 #include <errno.h>
44 #include <stdlib.h>
45 #include <sys/types.h>
46 /*
47 #include <sys/resource.h>
48 */
49 #include <sys/wait.h>
50 #include "../../core/mem/mem.h"
51 #include "../../core/error.h"
52 #include "../../core/config.h"
53 #include "../../core/parser/msg_parser.h"
54 #include "../../core/dprint.h"
55 #include "../../core/dset.h"
56 #include "../../core/action.h"
57 #include "../../core/usr_avp.h"
58 
59 #include "exec.h"
60 
exec_msg(struct sip_msg * msg,char * cmd)61 int exec_msg(struct sip_msg *msg, char *cmd)
62 {
63 	FILE *pipe;
64 	int exit_status;
65 	int ret;
66 
67 	ret = -1; /* pessimist: assume error */
68 	pipe = popen(cmd, "w");
69 	if(pipe == NULL) {
70 		LM_ERR("cannot open pipe: %s\n", cmd);
71 		ser_error = E_EXEC;
72 		return -1;
73 	}
74 
75 	if(fwrite(msg->buf, 1, msg->len, pipe) != msg->len) {
76 		LM_ERR("failed to write to pipe\n");
77 		ser_error = E_EXEC;
78 		goto error01;
79 	}
80 	/* success */
81 	ret = 1;
82 
83 error01:
84 	if(ferror(pipe)) {
85 		LM_ERR("pipe: %s\n", strerror(errno));
86 		ser_error = E_EXEC;
87 		ret = -1;
88 	}
89 	exit_status = pclose(pipe);
90 	if(WIFEXITED(exit_status)) { /* exited properly .... */
91 		/* return false if script exited with non-zero status */
92 		if(WEXITSTATUS(exit_status) != 0)
93 			ret = -1;
94 	} else { /* exited erroneously */
95 		LM_ERR("cmd %s failed. exit_status=%d, errno=%d: %s\n", cmd,
96 				exit_status, errno, strerror(errno));
97 		ret = -1;
98 	}
99 	return ret;
100 }
101 
exec_str(struct sip_msg * msg,char * cmd,char * param,int param_len)102 int exec_str(struct sip_msg *msg, char *cmd, char *param, int param_len)
103 {
104 
105 	struct action act;
106 	struct run_act_ctx ra_ctx;
107 	int cmd_len;
108 	FILE *pipe;
109 	char *cmd_line;
110 	int ret;
111 	int l1;
112 	static char uri_line[MAX_URI_SIZE + 1];
113 	int uri_cnt;
114 	str uri;
115 	int exit_status;
116 
117 	/* pessimist: assume error by default */
118 	ret = -1;
119 
120 	l1 = strlen(cmd);
121 	if(param_len > 0)
122 		cmd_len = l1 + param_len + 4;
123 	else
124 		cmd_len = l1 + 1;
125 	cmd_line = pkg_malloc(cmd_len);
126 	if(cmd_line == 0) {
127 		ret = ser_error = E_OUT_OF_MEM;
128 		LM_ERR("no pkg mem for command\n");
129 		goto error00;
130 	}
131 
132 	/* 'command parameter \0' */
133 	memcpy(cmd_line, cmd, l1);
134 	if(param_len > 0) {
135 		cmd_line[l1] = ' ';
136 		cmd_line[l1 + 1] = '\'';
137 		memcpy(cmd_line + l1 + 2, param, param_len);
138 		cmd_line[l1 + param_len + 2] = '\'';
139 		cmd_line[l1 + param_len + 3] = 0;
140 	} else {
141 		cmd_line[l1] = 0;
142 	}
143 
144 	pipe = popen(cmd_line, "r");
145 	if(pipe == NULL) {
146 		LM_ERR("cannot open pipe: %s\n", cmd_line);
147 		ser_error = E_EXEC;
148 		goto error01;
149 	}
150 
151 	/* read now line by line */
152 	uri_cnt = 0;
153 	while(fgets(uri_line, MAX_URI_SIZE, pipe) != NULL) {
154 		uri.s = uri_line;
155 		uri.len = strlen(uri.s);
156 		/* trim from right */
157 		while(uri.len
158 				&& (uri.s[uri.len - 1] == '\r' || uri.s[uri.len - 1] == '\n'
159 						   || uri.s[uri.len - 1] == '\t'
160 						   || uri.s[uri.len - 1] == ' ')) {
161 			LM_DBG("rtrim\n");
162 			uri.len--;
163 		}
164 		/* skip empty line */
165 		if(uri.len == 0)
166 			continue;
167 		/* ZT */
168 		uri.s[uri.len] = 0;
169 		if(uri_cnt == 0) {
170 			memset(&act, 0, sizeof(act));
171 			act.type = SET_URI_T;
172 			act.val[0].type = STRING_ST;
173 			act.val[0].u.string = uri.s;
174 			init_run_actions_ctx(&ra_ctx);
175 			if(do_action(&ra_ctx, &act, msg) < 0) {
176 				LM_ERR("the action for has failed\n");
177 				ser_error = E_OUT_OF_MEM;
178 				goto error02;
179 			}
180 		} else {
181 			if(append_branch(msg, &uri, 0, 0, Q_UNSPECIFIED, 0, 0, 0, 0, 0, 0)
182 					== -1) {
183 				LM_ERR("append_branch failed; too many or too long URIs?\n");
184 				goto error02;
185 			}
186 		}
187 		uri_cnt++;
188 	}
189 	if(uri_cnt == 0) {
190 		LM_ERR("no uri from %s\n", cmd_line);
191 		goto error02;
192 	}
193 	/* success */
194 	ret = 1;
195 
196 error02:
197 	if(ferror(pipe)) {
198 		LM_ERR("in pipe: %s\n", strerror(errno));
199 		ser_error = E_EXEC;
200 		ret = -1;
201 	}
202 	exit_status = pclose(pipe);
203 	if(WIFEXITED(exit_status)) { /* exited properly .... */
204 		/* return false if script exited with non-zero status */
205 		if(WEXITSTATUS(exit_status) != 0)
206 			ret = -1;
207 	} else { /* exited erroneously */
208 		LM_ERR("cmd %s failed. exit_status=%d, errno=%d: %s\n", cmd,
209 				exit_status, errno, strerror(errno));
210 		ret = -1;
211 	}
212 error01:
213 	pkg_free(cmd_line);
214 error00:
215 	return ret;
216 }
217 
218 
exec_avp(struct sip_msg * msg,char * cmd,pvname_list_p avpl)219 int exec_avp(struct sip_msg *msg, char *cmd, pvname_list_p avpl)
220 {
221 	int_str avp_val;
222 	int_str avp_name;
223 	unsigned short avp_type;
224 	FILE *pipe;
225 	int ret;
226 	char res_line[MAX_URI_SIZE + 1];
227 	str res;
228 	int exit_status;
229 	int i;
230 	pvname_list_t *crt;
231 
232 	/* pessimist: assume error by default */
233 	ret = -1;
234 
235 	pipe = popen(cmd, "r");
236 	if(pipe == NULL) {
237 		LM_ERR("cannot open pipe: %s\n", cmd);
238 		ser_error = E_EXEC;
239 		return ret;
240 	}
241 
242 	/* read now line by line */
243 	i = 0;
244 	crt = avpl;
245 	while(fgets(res_line, MAX_URI_SIZE, pipe) != NULL) {
246 		res.s = res_line;
247 		res.len = strlen(res.s);
248 		/* trim from right */
249 		while(res.len
250 				&& (res.s[res.len - 1] == '\r' || res.s[res.len - 1] == '\n'
251 						   || res.s[res.len - 1] == '\t'
252 						   || res.s[res.len - 1] == ' ')) {
253 			res.len--;
254 		}
255 		/* skip empty line */
256 		if(res.len == 0)
257 			continue;
258 		/* ZT */
259 		res.s[res.len] = 0;
260 
261 		avp_type = 0;
262 		if(crt == NULL) {
263 			avp_name.n = i + 1;
264 		} else {
265 			if(pv_get_avp_name(msg, &(crt->sname.pvp), &avp_name, &avp_type)
266 					!= 0) {
267 				LM_ERR("can't get item name [%d]\n", i);
268 				goto error;
269 			}
270 		}
271 
272 		avp_type |= AVP_VAL_STR;
273 		avp_val.s = res;
274 
275 		if(add_avp(avp_type, avp_name, avp_val) != 0) {
276 			LM_ERR("unable to add avp\n");
277 			goto error;
278 		}
279 
280 		if(crt)
281 			crt = crt->next;
282 
283 		i++;
284 	}
285 	if(i == 0) {
286 		LM_DBG("no result from %s\n", cmd);
287 	} else {
288 		LM_DBG("%d results from %s\n", i, cmd);
289 	}
290 	/* success */
291 	ret = 1;
292 
293 error:
294 	if(ferror(pipe)) {
295 		LM_ERR("pipe: %d/%s\n", errno, strerror(errno));
296 		ser_error = E_EXEC;
297 		ret = -1;
298 	}
299 	exit_status = pclose(pipe);
300 	if(WIFEXITED(exit_status)) { /* exited properly .... */
301 		/* return false if script exited with non-zero status */
302 		if(WEXITSTATUS(exit_status) != 0)
303 			ret = -1;
304 	} else { /* exited erroneously */
305 		LM_ERR("cmd %s failed. exit_status=%d, errno=%d: %s\n", cmd,
306 				exit_status, errno, strerror(errno));
307 		ret = -1;
308 	}
309 	return ret;
310 }
311 
exec_cmd(sip_msg_t * msg,char * cmd)312 int exec_cmd(sip_msg_t *msg, char *cmd)
313 {
314 	FILE *pipe;
315 	int exit_status;
316 	int ret;
317 
318 	pipe = popen(cmd, "r");
319 	if(pipe == NULL) {
320 		LM_ERR("cannot open pipe: %s\n", cmd);
321 		ser_error = E_EXEC;
322 		return -1;
323 	}
324 
325 	ret = 1;
326 	exit_status = pclose(pipe);
327 	if(WIFEXITED(exit_status)) { /* exited properly .... */
328 		/* return false if script exited with non-zero status */
329 		if(WEXITSTATUS(exit_status) != 0) {
330 			LM_DBG("cmd %s with non-zero status - exit_status=%d,"
331 					" wexitstatus: %d, errno=%d: %s\n",
332 					cmd, exit_status, WEXITSTATUS(exit_status),
333 					errno, strerror(errno));
334 			ret = -1;
335 		}
336 	} else { /* exited erroneously */
337 		LM_ERR("cmd %s failed. exit_status=%d, wexitstatus: %d, errno=%d: %s\n",
338 				cmd, exit_status, WEXITSTATUS(exit_status),
339 				errno, strerror(errno));
340 		ret = -1;
341 	}
342 
343 	return ret;
344 }
345