OpenVAS Scanner  22.7.9
nasl_cmd_exec.c
Go to the documentation of this file.
1 /* SPDX-FileCopyrightText: 2023 Greenbone AG
2  * SPDX-FileCopyrightText: 2002-2004 Tenable Network Security
3  *
4  * SPDX-License-Identifier: GPL-2.0-only
5  */
6 
12 #include "nasl_cmd_exec.h"
13 
14 #include "../misc/plugutils.h"
15 #include "nasl_debug.h"
16 #include "nasl_func.h"
17 #include "nasl_global_ctxt.h"
18 #include "nasl_lex_ctxt.h"
19 #include "nasl_tree.h"
20 #include "nasl_var.h"
21 
22 #include <errno.h> /* for errno */
23 #include <fcntl.h> /* for open */
24 #include <glib.h> /* for g_get_tmp_dir */
25 #include <gvm/base/drop_privileges.h> /* for drop_privileges */
26 #include <gvm/base/prefs.h> /* for prefs_get_bool() */
27 #include <signal.h> /* for kill */
28 #include <string.h> /* for strncpy */
29 #include <sys/param.h> /* for MAXPATHLEN */
30 #include <sys/stat.h> /* for stat */
31 #include <sys/wait.h> /* for waitpid */
32 #include <unistd.h> /* for getcwd */
33 
34 /* MAXPATHLEN doesn't exist on some architectures like hurd i386 */
35 #ifndef MAXPATHLEN
36 #define MAXPATHLEN 4096
37 #endif
38 
39 static pid_t pid = 0;
40 
41 static char *
42 pread_streams (int fdout, int fderr)
43 {
44  GString *str;
45 
46  str = g_string_new ("");
47  errno = 0;
48  for (;;)
49  {
50  fd_set fds;
51  char buf[8192];
52  int ret, ret_out = 0, ret_err = 0;
53  int maxfd = fdout > fderr ? fdout : fderr;
54 
55  FD_ZERO (&fds);
56  FD_SET (fdout, &fds);
57  FD_SET (fderr, &fds);
58 
59  ret = select (maxfd + 1, &fds, NULL, NULL, NULL);
60  if (ret == -1)
61  {
62  if (errno == EINTR)
63  continue;
64  return NULL;
65  }
66  bzero (buf, sizeof (buf));
67  if (FD_ISSET (fdout, &fds))
68  {
69  ret_out = read (fdout, buf, sizeof (buf));
70  if (ret_out > 0)
71  g_string_append (str, buf);
72  }
73  if (FD_ISSET (fderr, &fds))
74  {
75  ret_err = read (fderr, buf, sizeof (buf));
76  if (ret_err > 0)
77  g_string_append (str, buf);
78  }
79  if (ret_out <= 0 && ret_err <= 0)
80  break;
81  }
82 
83  return g_string_free (str, FALSE);
84 }
85 
99 tree_cell *
101 {
102  tree_cell *retc = NULL, *a;
103  anon_nasl_var *v;
104  nasl_array *av;
105  int i, j, n, cd, fdout = 0, fderr = 0;
106  char **args = NULL, *cmd, *str, *new_user;
107  char cwd[MAXPATHLEN], newdir[MAXPATHLEN];
108  GError *error = NULL;
109 
110  if (pid != 0)
111  {
112  nasl_perror (lexic, "nasl_pread is not reentrant!\n");
113  return NULL;
114  }
115 
116  new_user = get_str_var_by_name (lexic, "drop_privileges_user");
117  if (new_user && !prefs_get_bool ("drop_privileges"))
118  {
119  if (drop_privileges (new_user, &error))
120  {
121  if (error)
122  {
123  nasl_perror (lexic, "%s: %s\n", __func__, error->message);
124  g_error_free (error);
125  }
126  return NULL;
127  }
128  }
129 
130  a = get_variable_by_name (lexic, "argv");
131  cmd = get_str_var_by_name (lexic, "cmd");
132  if (cmd == NULL || a == NULL || (v = a->x.ref_val) == NULL)
133  {
134  deref_cell (a);
135  nasl_perror (lexic, "pread() usage: cmd:..., argv:...\n");
136  return NULL;
137  }
138  deref_cell (a);
139 
140  if (v->var_type == VAR2_ARRAY)
141  av = &v->v.v_arr;
142  else
143  {
144  nasl_perror (lexic, "pread: argv element must be an array (0x%x)\n",
145  v->var_type);
146  return NULL;
147  }
148 
149  cd = get_int_var_by_name (lexic, "cd", 0);
150 
151  cwd[0] = '\0';
152  if (cd)
153  {
154  char *p;
155 
156  memset (newdir, '\0', sizeof (newdir));
157  if (cmd[0] == '/')
158  strncpy (newdir, cmd, sizeof (newdir) - 1);
159  else
160  {
161  p = g_find_program_in_path (cmd);
162  if (p != NULL)
163  strncpy (newdir, p, sizeof (newdir) - 1);
164  else
165  {
166  nasl_perror (lexic, "pread: '%s' not found in $PATH\n", cmd);
167  return NULL;
168  }
169  g_free (p);
170  }
171  p = strrchr (newdir, '/');
172  if (p && p != newdir)
173  *p = '\0';
174  if (getcwd (cwd, sizeof (cwd)) == NULL)
175  {
176  nasl_perror (lexic, "pread(): getcwd: %s\n", strerror (errno));
177  *cwd = '\0';
178  }
179 
180  if (chdir (newdir) < 0)
181  {
182  nasl_perror (lexic, "pread: could not chdir to %s\n", newdir);
183  return NULL;
184  }
185  if (cmd[0] != '/' && strlen (newdir) + strlen (cmd) + 1 < sizeof (newdir))
186  {
187  strcat (newdir, "/");
188  strcat (newdir, cmd);
189  }
190  }
191 
192  if (av->hash_elt != NULL)
193  nasl_perror (lexic, "pread: named elements in 'cmd' are ignored!\n");
194  n = av->max_idx;
195  args = g_malloc0 (sizeof (char *) * (n + 2)); /* Last arg is NULL */
196  for (j = 0, i = 0; i < n; i++)
197  {
198  str = (char *) var2str (av->num_elt[i]);
199  if (str != NULL)
200  args[j++] = g_strdup (str);
201  }
202  args[j] = NULL;
203 
204  if (g_spawn_async_with_pipes (NULL, args, NULL, G_SPAWN_SEARCH_PATH, NULL,
205  NULL, &pid, NULL, &fdout, &fderr, &error)
206  == FALSE)
207  {
208  if (error)
209  {
210  g_warning ("%s: %s", __func__, error->message);
211  g_error_free (error);
212  }
213  goto finish_pread;
214  }
215 
216  str = pread_streams (fdout, fderr);
217  if (str)
218  {
219  retc = alloc_typed_cell (CONST_DATA);
220  retc->x.str_val = str;
221  retc->size = strlen (str);
222  }
223  else if (errno && errno != EINTR)
224  nasl_perror (lexic, "nasl_pread: fread(): %s\n", strerror (errno));
225  close (fdout);
226  close (fderr);
227  if (*cwd != '\0')
228  if (chdir (cwd) < 0)
229  nasl_perror (lexic, "pread(): chdir(%s): %s\n", cwd, strerror (errno));
230 
231 finish_pread:
232  for (i = 0; i < n; i++)
233  g_free (args[i]);
234  g_free (args);
235 
236  g_spawn_close_pid (pid);
237  pid = 0;
238 
239  return retc;
240 }
241 
242 tree_cell *
244 {
245  tree_cell *retc;
246  char *cmd, *result;
247 
248  cmd = get_str_var_by_num (lexic, 0);
249  if (cmd == NULL)
250  {
251  nasl_perror (lexic, "find_in_path() usage: cmd\n");
252  return NULL;
253  }
254 
255  retc = alloc_typed_cell (CONST_INT);
256  result = g_find_program_in_path (cmd);
257  retc->x.i_val = !!result;
258  g_free (result);
259  return retc;
260 }
261 
262 /*
263  * Not a command, but dangerous anyway
264  */
269 tree_cell *
271 {
272  tree_cell *retc;
273  char *fname, *fcontent;
274  size_t flen;
275  GError *ferror = NULL;
276 
277  fname = get_str_var_by_num (lexic, 0);
278  if (fname == NULL)
279  {
280  nasl_perror (lexic, "fread: need one argument (file name)\n");
281  return NULL;
282  }
283 
284  if (!g_file_get_contents (fname, &fcontent, &flen, &ferror))
285  {
286  nasl_perror (lexic, "fread: %s", ferror ? ferror->message : "Error");
287  if (ferror)
288  g_error_free (ferror);
289  return NULL;
290  }
291 
292  retc = alloc_typed_cell (CONST_DATA);
293  retc->size = flen;
294  retc->x.str_val = fcontent;
295  return retc;
296 }
297 
298 /*
299  * Not a command, but dangerous anyway
300  */
305 tree_cell *
307 {
308  char *fname;
309 
310  fname = get_str_var_by_num (lexic, 0);
311  if (fname == NULL)
312  {
313  nasl_perror (lexic, "unlink: need one argument (file name)\n");
314  return NULL;
315  }
316 
317  if (unlink (fname) < 0)
318  {
319  nasl_perror (lexic, "unlink(%s): %s\n", fname, strerror (errno));
320  return NULL;
321  }
322  /* No need to return a value */
323  return FAKE_CELL;
324 }
325 
326 /* Definitely dangerous too */
330 tree_cell *
332 {
333  tree_cell *retc;
334  char *fcontent, *fname;
335  size_t flen;
336  GError *ferror = NULL;
337 
338  fcontent = get_str_var_by_name (lexic, "data");
339  fname = get_str_var_by_name (lexic, "file");
340  if (!fcontent || !fname)
341  {
342  nasl_perror (lexic, "fwrite: need two arguments 'data' and 'file'\n");
343  return NULL;
344  }
345  flen = get_var_size_by_name (lexic, "data");
346 
347  if (!g_file_set_contents (fname, fcontent, flen, &ferror))
348  {
349  nasl_perror (lexic, "fwrite: %s", ferror ? ferror->message : "Error");
350  if (ferror)
351  g_error_free (ferror);
352  return NULL;
353  }
354  retc = alloc_typed_cell (CONST_INT);
355  retc->x.i_val = flen;
356  return retc;
357 }
358 
359 tree_cell *
361 {
362  tree_cell *retc;
363  char path[MAXPATHLEN];
364 
365  snprintf (path, sizeof (path), "%s/", g_get_tmp_dir ());
366  if (access (path, R_OK | W_OK | X_OK) < 0)
367  {
368  nasl_perror (
369  lexic,
370  "get_tmp_dir(): %s not available - check your OpenVAS installation\n",
371  path);
372  return NULL;
373  }
374 
375  retc = alloc_typed_cell (CONST_DATA);
376  retc->x.str_val = strdup (path);
377  retc->size = strlen (retc->x.str_val);
378 
379  return retc;
380 }
381 
382 /*
383  * File access functions : Dangerous
384  */
385 
390 tree_cell *
392 {
393  tree_cell *retc;
394  char *fname;
395  struct stat st;
396 
397  fname = get_str_var_by_num (lexic, 0);
398  if (fname == NULL)
399  {
400  nasl_perror (lexic, "file_stat: need one argument (file name)\n");
401  return NULL;
402  }
403 
404  if (stat (fname, &st) < 0)
405  return NULL;
406 
407  retc = alloc_typed_cell (CONST_INT);
408  retc->x.i_val = (int) st.st_size;
409  return retc;
410 }
411 
415 tree_cell *
417 {
418  tree_cell *retc;
419  char *fname, *mode;
420  struct stat fstat_info;
421  int fd;
422  int imode = O_RDONLY;
423 
424  fname = get_str_var_by_name (lexic, "name");
425  if (fname == NULL)
426  {
427  nasl_perror (lexic, "file_open: need file name argument\n");
428  return NULL;
429  }
430 
431  mode = get_str_var_by_name (lexic, "mode");
432  if (mode == NULL)
433  {
434  nasl_perror (lexic, "file_open: need file mode argument\n");
435  return NULL;
436  }
437 
438  if (strcmp (mode, "r") == 0)
439  imode = O_RDONLY;
440  else if (strcmp (mode, "w") == 0)
441  imode = O_WRONLY | O_CREAT;
442  else if (strcmp (mode, "w+") == 0)
443  imode = O_WRONLY | O_TRUNC | O_CREAT;
444  else if (strcmp (mode, "a") == 0)
445  imode = O_WRONLY | O_APPEND | O_CREAT;
446  else if (strcmp (mode, "a+") == 0)
447  imode = O_RDWR | O_APPEND | O_CREAT;
448 
449  fd = open (fname, imode, 0600);
450  if (fd < 0)
451  {
452  nasl_perror (lexic, "file_open: %s: possible symlink attack!?! %s\n",
453  fname, strerror (errno));
454  return NULL;
455  }
456 
457  if (fstat (fd, &fstat_info) == -1)
458  {
459  close (fd);
460  nasl_perror (lexic, "fread: %s: possible symlink attack!?! %s\n", fname,
461  strerror (errno));
462  return NULL;
463  }
464 
465  retc = alloc_typed_cell (CONST_INT);
466  retc->x.i_val = fd;
467  return retc;
468 }
469 
473 tree_cell *
475 {
476  tree_cell *retc;
477  int fd;
478 
479  fd = get_int_var_by_num (lexic, 0, -1);
480  if (fd < 0)
481  {
482  nasl_perror (lexic, "file_close: need file pointer argument\n");
483  return NULL;
484  }
485 
486  if (close (fd) < 0)
487  {
488  nasl_perror (lexic, "file_close: %s\n", strerror (errno));
489  return NULL;
490  }
491 
492  retc = alloc_typed_cell (CONST_INT);
493  retc->x.i_val = 0;
494  return retc;
495 }
496 
500 tree_cell *
502 {
503  tree_cell *retc;
504  char *buf;
505  int fd;
506  int flength;
507  int n;
508 
509  fd = get_int_var_by_name (lexic, "fp", -1);
510  if (fd < 0)
511  {
512  nasl_perror (lexic, "file_read: need file pointer argument\n");
513  return NULL;
514  }
515 
516  flength = get_int_var_by_name (lexic, "length", 0);
517 
518  buf = g_malloc0 (flength + 1);
519 
520  for (n = 0; n < flength;)
521  {
522  int e;
523  errno = 0;
524  e = read (fd, buf + n, flength - n);
525  if (e < 0 && errno == EINTR)
526  continue;
527  else if (e <= 0)
528  break;
529  else
530  n += e;
531  }
532 
533  retc = alloc_typed_cell (CONST_DATA);
534  retc->size = n;
535  retc->x.str_val = buf;
536  return retc;
537 }
538 
542 tree_cell *
544 {
545  tree_cell *retc;
546  char *content;
547  int len;
548  int fd;
549  int n;
550 
551  content = get_str_var_by_name (lexic, "data");
552  fd = get_int_var_by_name (lexic, "fp", -1);
553  if (content == NULL || fd < 0)
554  {
555  nasl_perror (lexic, "file_write: need two arguments 'fp' and 'data'\n");
556  return NULL;
557  }
558  len = get_var_size_by_name (lexic, "data");
559 
560  for (n = 0; n < len;)
561  {
562  int e;
563  errno = 0;
564  e = write (fd, content + n, len - n);
565  if (e < 0 && errno == EINTR)
566  continue;
567  else if (e <= 0)
568  {
569  nasl_perror (lexic, "file_write: write() failed - %s\n",
570  strerror (errno));
571  break;
572  }
573  else
574  n += e;
575  }
576 
577  retc = alloc_typed_cell (CONST_INT);
578  retc->x.i_val = n;
579  return retc;
580 }
581 
585 tree_cell *
587 {
588  tree_cell *retc;
589  int fd;
590  int foffset;
591 
592  foffset = get_int_var_by_name (lexic, "offset", 0);
593  fd = get_int_var_by_name (lexic, "fp", -1);
594  if (fd < 0)
595  {
596  nasl_perror (lexic, "file_seek: need one arguments 'fp'\n");
597  return NULL;
598  }
599 
600  if (lseek (fd, foffset, SEEK_SET) < 0)
601  {
602  nasl_perror (lexic, "fseek: %s\n", strerror (errno));
603  return NULL;
604  }
605 
606  retc = alloc_typed_cell (CONST_INT);
607  retc->x.i_val = 0;
608  return retc;
609 }
st_a_nasl_var
Definition: nasl_var.h:40
CONST_DATA
@ CONST_DATA
Definition: nasl_tree.h:82
nasl_file_read
tree_cell * nasl_file_read(lex_ctxt *lexic)
Read file.
Definition: nasl_cmd_exec.c:501
nasl_file_write
tree_cell * nasl_file_write(lex_ctxt *lexic)
Write file.
Definition: nasl_cmd_exec.c:543
get_var_size_by_name
int get_var_size_by_name(lex_ctxt *, const char *)
Definition: nasl_var.c:1138
nasl_file_stat
tree_cell * nasl_file_stat(lex_ctxt *lexic)
Stat file.
Definition: nasl_cmd_exec.c:391
TC::str_val
char * str_val
Definition: nasl_tree.h:103
var2str
const char * var2str(anon_nasl_var *v)
Definition: nasl_var.c:1065
st_nasl_array::max_idx
int max_idx
Definition: nasl_var.h:34
st_a_nasl_var::v_arr
nasl_array v_arr
Definition: nasl_var.h:49
TC::x
union TC::@5 x
st_nasl_array::hash_elt
struct st_n_nasl_var ** hash_elt
Definition: nasl_var.h:36
FAKE_CELL
#define FAKE_CELL
Definition: nasl_tree.h:110
nasl_file_seek
tree_cell * nasl_file_seek(lex_ctxt *lexic)
Seek in file.
Definition: nasl_cmd_exec.c:586
st_a_nasl_var::v
union st_a_nasl_var::@7 v
get_str_var_by_name
char * get_str_var_by_name(lex_ctxt *, const char *)
Definition: nasl_var.c:1118
nasl_file_open
tree_cell * nasl_file_open(lex_ctxt *lexic)
Open file.
Definition: nasl_cmd_exec.c:416
st_nasl_array
Definition: nasl_var.h:33
pread_streams
static char * pread_streams(int fdout, int fderr)
Definition: nasl_cmd_exec.c:42
nasl_pread
tree_cell * nasl_pread(lex_ctxt *lexic)
Spawn a process.
Definition: nasl_cmd_exec.c:100
nasl_debug.h
nasl_fread
tree_cell * nasl_fread(lex_ctxt *lexic)
Read file.
Definition: nasl_cmd_exec.c:270
nasl_file_close
tree_cell * nasl_file_close(lex_ctxt *lexic)
Close file.
Definition: nasl_cmd_exec.c:474
nasl_perror
void nasl_perror(lex_ctxt *lexic, char *msg,...)
Definition: nasl_debug.c:111
pid
static pid_t pid
Definition: nasl_cmd_exec.c:39
TC::size
int size
Definition: nasl_tree.h:99
nasl_fwrite
tree_cell * nasl_fwrite(lex_ctxt *lexic)
Write file.
Definition: nasl_cmd_exec.c:331
nasl_lex_ctxt.h
len
uint8_t len
Definition: nasl_packet_forgery.c:1
get_int_var_by_name
long int get_int_var_by_name(lex_ctxt *, const char *, int)
Definition: nasl_var.c:1104
VAR2_ARRAY
@ VAR2_ARRAY
Definition: nasl_var.h:19
nasl_func.h
get_int_var_by_num
long int get_int_var_by_num(lex_ctxt *, int, int)
Definition: nasl_var.c:1097
get_str_var_by_num
char * get_str_var_by_num(lex_ctxt *, int)
Definition: nasl_var.c:1111
st_a_nasl_var::var_type
int var_type
Definition: nasl_var.h:41
TC
Definition: nasl_tree.h:94
struct_lex_ctxt
Definition: nasl_lex_ctxt.h:23
nasl_var.h
nasl_cmd_exec.h
nasl_find_in_path
tree_cell * nasl_find_in_path(lex_ctxt *lexic)
Definition: nasl_cmd_exec.c:243
nasl_global_ctxt.h
CONST_INT
@ CONST_INT
Definition: nasl_tree.h:79
nasl_get_tmp_dir
tree_cell * nasl_get_tmp_dir(lex_ctxt *lexic)
Definition: nasl_cmd_exec.c:360
MAXPATHLEN
#define MAXPATHLEN
Definition: nasl_cmd_exec.c:36
deref_cell
void deref_cell(tree_cell *c)
Definition: nasl_tree.c:181
alloc_typed_cell
tree_cell * alloc_typed_cell(int typ)
Definition: nasl_tree.c:28
get_variable_by_name
tree_cell * get_variable_by_name(lex_ctxt *, const char *)
Definition: nasl_var.c:179
nasl_unlink
tree_cell * nasl_unlink(lex_ctxt *lexic)
Unlink file.
Definition: nasl_cmd_exec.c:306
nasl_tree.h
TC::i_val
long int i_val
Definition: nasl_tree.h:104
st_nasl_array::num_elt
struct st_a_nasl_var ** num_elt
Definition: nasl_var.h:35