source: trunk/src/sh_extern.c @ 491

Last change on this file since 491 was 491, checked in by katerina, 6 years ago

Fix for ticket #389 (libwrap) and #390 (update on FreeBSD).

File size: 37.3 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 2000,2004 Rainer Wichmann                                 */
3/*                                                                         */
4/*  This program is free software; you can redistribute it                 */
5/*  and/or modify                                                          */
6/*  it under the terms of the GNU General Public License as                */
7/*  published by                                                           */
8/*  the Free Software Foundation; either version 2 of the License, or      */
9/*  (at your option) any later version.                                    */
10/*                                                                         */
11/*  This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.              */
19
20
21#include "config_xor.h"
22
23
24#include <stdio.h>
25#include <string.h>
26#ifdef HAVE_MEMORY_H
27#include <memory.h>
28#endif
29
30/* replace #if 0 by #if 1 and set an appropriate path in front of '/pdbg.'
31 * for debugging
32 */
33#if 0
34#define PDGBFILE "/pdbg."
35#endif
36
37
38#if defined(PDGBFILE)
39static FILE * pdbg = NULL;
40static FILE * pdbgc = NULL;
41#define PDBG_OPEN    if (pdbg == NULL) pdbg = fopen(PDGBFILE"main",  "a") 
42#define PDBG_CLOSE   sl_fclose (FIL__, __LINE__, pdbg); pdbg = NULL
43#define PDBG(arg)    fprintf(pdbg,  "PDBG: step %d\n", arg); fflush(pdbg)
44#define PDBG_D(arg)  fprintf(pdbg,  "PDBG: %d\n", arg); fflush(pdbg)
45#define PDBG_S(arg)  fprintf(pdbg,  "PDBG: %s\n", arg); fflush(pdbg)
46
47#define PDBGC_OPEN   if (pdbgc == NULL) pdbgc = fopen(PDGBFILE"child", "a") 
48#define PDBGC_CLOSE  sl_fclose (FIL__, __LINE__, pdbgc); pdbgc = NULL
49#define PDBGC(arg)   fprintf(pdbgc, "PDBGC: step %d\n", arg); fflush(pdbgc)
50#define PDBGC_D(arg) fprintf(pdbgc, "PDBGC: %d\n", arg); fflush(pdbgc)
51#define PDBGC_S(arg) fprintf(pdbgc, "PDBGC: %s\n", arg); fflush(pdbgc)
52#else
53#define PDBG_OPEN   
54#define PDBG_CLOSE   
55#define PDBG(arg)   
56#define PDBG_D(arg) 
57#define PDBG_S(arg) 
58#define PDBGC_OPEN   
59#define PDBGC_CLOSE   
60#define PDBGC(arg)   
61#define PDBGC_D(arg) 
62#define PDBGC_S(arg) 
63#endif
64
65
66#include <stdlib.h>
67#include <pwd.h>
68#include <unistd.h>
69#include <fcntl.h>
70#include <signal.h>
71#include <sys/stat.h>
72#include <sys/types.h>
73#include <errno.h>
74#include <sys/wait.h>
75
76#if TIME_WITH_SYS_TIME
77#include <sys/time.h>
78#include <time.h>
79#else
80#if HAVE_SYS_TIME_H
81#include <sys/time.h>
82#else
83#include <time.h>
84#endif
85#endif
86
87
88#include "samhain.h"
89#include "sh_utils.h"
90#include "sh_unix.h"
91#include "sh_tiger.h"
92#include "sh_extern.h"
93#include "sh_calls.h"
94#include "sh_filter.h"
95#define SH_NEED_PWD_GRP 1
96#include "sh_static.h"
97
98
99#undef  FIL__
100#define FIL__  _("sh_extern.c")
101
102extern int get_the_fd (SL_TICKET ticket);
103
104/*
105 * -- generic safe popen
106 */
107
108int sh_ext_popen (sh_tas_t * task)
109{
110  long status = 0;
111  int    flags;
112  char * tmp;
113  char * tmp2;
114  int    errnum;
115  int    pipedes[2];
116  FILE * outf = NULL;
117  char * envp[1];
118  char * argp[2];
119
120  char * errfile;
121  char errbuf[SH_ERRBUF_SIZE];
122
123  static int some_error = 0;
124
125#if defined (__linux__)
126  SL_TICKET   fd  = -1;
127  char        pname[128];
128  int         pfd = -1;
129#endif
130
131  SL_ENTER(_("sh_ext_popen"));
132
133  /* Linux, HP-UX and FreeBSD will happily accept envp = argp = NULL
134   * (newer Linuxes (gcc 4.4.4) warn on argp == NULL, but accept it,
135   * as reported by T. Luettgert)
136   * Solaris (and probably some other Unices)
137   *         needs a valid *envp[] with envp[0] = NULL;
138   *         and similarly for argp
139   * OpenBSD finally needs non-null argp[0] ...
140   */
141  argp[0] = task->command;
142  argp[1] = NULL;
143  envp[0] = NULL;
144
145  /*
146   * --  check whether path is trustworthy
147   */
148  status = sl_trustfile(task->command, NULL, NULL);
149#if 0
150  if ((uid_t) -1 != task->trusted_users[0])
151    {
152      status = sl_trustfile(task->command, task->trusted_users, NULL);
153    }
154#endif
155
156  PDBG_OPEN;
157  PDBG_D( (int) status);
158
159  if ( SL_ENONE != status)
160    { 
161      PDBG_S("SL_ENONE != status");
162      if (some_error == 0)
163        {
164          tmp  = sh_util_safe_name (task->command);
165          errfile = sl_trust_errfile();
166          if (errfile[0] != '\0')
167            {
168              tmp2  = sh_util_safe_name (sl_trust_errfile());
169              sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_TRUST2,
170                              sl_error_string((int)status), tmp, tmp2);
171              SH_FREE(tmp2); 
172            }
173          else
174            {
175              sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_TRUST1,
176                              sl_error_string((int)status), tmp);
177            }
178          SH_FREE(tmp);
179        }
180      some_error = 1;
181      SL_RETURN ((-1), _("sh_ext_popen"));
182    }
183
184  PDBG(1);
185
186  /*
187   * --  check whether the checksum is correct; with linux emulate fdexec
188   */
189#if ( !defined(__linux__) || ( defined(__linux__) && defined(HAVE_PTHREAD)) ) && !defined(SL_DEBUG)
190  if (task->checksum[0]  != '\0')
191    {
192      char hashbuf[KEYBUF_SIZE];
193      PDBG_S("checksum test");
194      if (0 != sl_strcmp(task->checksum, 
195                         sh_tiger_hash (task->command, TIGER_FILE, TIGER_NOLIM,
196                                        hashbuf, sizeof(hashbuf))
197                         )
198          )
199        {
200          PDBG_S("checksum mismatch");
201          if (some_error == 0)
202            {
203              tmp  = sh_util_safe_name (task->command);
204              sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_HASH, tmp);
205              SH_FREE(tmp);
206            }
207          some_error = 1;
208          SL_RETURN ((-1), _("sh_ext_popen"));
209        }
210    }
211#endif
212
213  some_error = 0;
214
215  PDBG(2);
216
217  /*
218   * -- Create the pipe
219   */
220  if (aud_pipe(FIL__, __LINE__, pipedes) < 0) 
221    {
222      PDBG_S("pipe() failure");
223      errnum = errno;
224      sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN, 
225                      sh_error_message(errnum, errbuf, sizeof(errbuf)), _("pipe"));
226      SL_RETURN ((-1), _("sh_ext_popen"));
227    }
228
229  PDBG(3);
230
231  /*
232   * -- Flush streams and fork
233   */
234  fflush (NULL);
235
236  task->pid = aud_fork(FIL__, __LINE__);
237
238  if (task->pid == (pid_t) - 1) 
239    {
240      PDBG_S("fork() failure");
241      /*@-usedef@*/
242      (void) sl_close_fd(FIL__, __LINE__, pipedes[0]);
243      (void) sl_close_fd(FIL__, __LINE__, pipedes[1]);
244      /*@+usedef@*/
245      errnum = errno;
246      sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN, 
247                      sh_error_message(errnum, errbuf, sizeof(errbuf)), _("fork"));
248      SL_RETURN ((-1), _("sh_ext_popen"));
249    }
250 
251  PDBG(4);
252
253  if (task->pid == (pid_t) 0) 
254    {
255      /*
256       * -- fork again, if requested
257       */
258      if (S_TRUE == task->fork_twice)
259        {
260          task->pid = fork();
261
262          if (task->pid == (pid_t) - 1) 
263            {
264              _exit (EXIT_FAILURE);
265            }
266        }
267
268      if (task->pid == (pid_t) 0)
269        {
270          int val_return;
271
272          PDBGC_OPEN;
273          PDBGC(1);
274
275          /*
276           * -- grandchild - make write side of the pipe stdin
277           */
278          if (task->rw == 'w')
279            {
280              do {
281                val_return = dup2 (pipedes[STDIN_FILENO], STDIN_FILENO);
282              } while (val_return < 0 && errno == EINTR);
283
284              if (val_return < 0)
285                _exit(EXIT_FAILURE);
286            }
287          else
288            {
289              do {
290                val_return = dup2 (pipedes[STDOUT_FILENO], STDOUT_FILENO);
291              } while (val_return < 0 && errno == EINTR);
292
293              if (val_return < 0)
294                _exit(EXIT_FAILURE);
295            }
296          PDBGC(2);
297           
298         
299          /* close the pipe descriptors
300           */
301          (void) sl_close_fd   (FIL__, __LINE__, pipedes[STDIN_FILENO]);
302          (void) sl_close_fd   (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
303         
304          /* don't leak file descriptors
305           */
306#if !defined(PDGBFILE)
307          sh_unix_closeall (3, task->com_fd, S_TRUE); /* in child process */
308#endif
309
310          /* drop root privileges, if possible && requested
311           */
312          if (task->privileged == 0 && 0 == getuid())
313            {
314              PDBGC_S("privileged");
315
316              /* zero priv info
317               */
318              memset(skey, 0, sizeof(sh_key_t));
319
320              if (setgid((gid_t) task->run_user_gid) != 0)
321                _exit(EXIT_FAILURE);
322              if (setuid((uid_t) task->run_user_uid) != 0)
323                _exit(EXIT_FAILURE);
324
325              /* make sure we cannot get root again
326               */
327              if (setuid(0) >= 0)
328                _exit(EXIT_FAILURE);
329            }
330         
331          PDBGC(3);
332          (void) fflush(NULL);
333         
334          if (task->rw == 'w')
335            {
336              PDBGC_S("w");
337              (void) fcntl  (STDOUT_FILENO, F_SETFD, FD_CLOEXEC);
338              (void) fcntl  (STDERR_FILENO, F_SETFD, FD_CLOEXEC);
339              /*
340              freopen(_("/dev/null"), "r+", stderr);
341              freopen(_("/dev/null"), "r+", stdout);
342              */
343            }
344          else
345            {
346              PDBGC_S("r");
347              do {
348                val_return = dup2 (STDOUT_FILENO, STDERR_FILENO);
349              } while (val_return < 0 && errno == EINTR);
350
351              (void) fcntl  (STDIN_FILENO, F_SETFD, FD_CLOEXEC);
352              /*
353              freopen(_("/dev/null"), "r+", stdin);
354              */
355            }
356         
357          PDBGC(4);
358         
359         
360#if defined(__linux__)
361          /*
362           * --  emulate an fdexec with checksum testing
363           */
364
365#if !defined(HAVE_PTHREAD)
366          if (task->checksum[0]  != '\0')
367#endif
368            {
369              PDBGC_S("fexecve");
370              if (task->com_fd != (-1))
371                {
372                  do {
373                    val_return = dup (task->com_fd);
374                  } while (val_return < 0 && errno == EINTR);
375                  pfd = val_return;
376                  if (pfd < 0)
377                    {
378                      PDBGC_S("fexecve: dup failed");
379                      _exit(EXIT_FAILURE);
380                    }
381                }
382#if !defined(HAVE_PTHREAD)
383              else
384                {
385                  char hashbuf[KEYBUF_SIZE];
386
387                  fd = 
388                    sl_open_read(FIL__, __LINE__, task->command, 
389                                 task->privileged==0 ? SL_NOPRIV : SL_YESPRIV);
390
391                  if (0 != sl_strcmp(task->checksum, 
392                                     sh_tiger_hash (task->command, 
393                                                    fd, TIGER_NOLIM, hashbuf, sizeof(hashbuf))))
394                    {
395                      PDBGC_S("fexecve: checksum mismatch");
396                      sl_close(fd);
397                      _exit(EXIT_FAILURE);
398                    }
399
400                  pfd = get_the_fd(fd);
401
402                  do {
403                    val_return = dup (pfd);
404                  } while (val_return < 0 && errno == EINTR);
405                  pfd = val_return;
406
407                  sl_close(fd);
408                  fd = -1;
409
410                  if (pfd < 0)
411                    {
412                      PDBGC_S("fexecve: dup (2) failed");
413                      _exit(EXIT_FAILURE);
414                    }
415                }
416#endif
417             
418              PDBGC(5);
419              /* Cannot use sprintf because of deadlock in malloc/free */
420              {
421                static char digit[] = "0123456789";
422                char str0[128];
423                char str1[128];
424                int ival = pfd;
425                unsigned int n = 0;
426                unsigned int m = 0;
427
428                if (ival < 0) ival = -ival;
429                do {
430                  str0[n] = digit[ival % 10];
431                  ++n;
432                  ival /= 10;
433                } while (ival);
434
435                if (pfd < 0)
436                  {
437                    str0[n] = '-';
438                    ++n;
439                  }
440                str0[n] = '\0';
441                str1[n] = '\0';
442                while (n > 0)
443                  {
444                    str1[m] = str0[n-1];
445                    ++m; --n;
446                  }
447                sl_strlcpy(pname, _("/proc/self/fd/"), sizeof(pname));
448                sl_strlcat(pname, str1, sizeof(pname));
449              }
450              if (access(pname, R_OK|X_OK) == 0) /* flawfinder: ignore */
451                {
452                  PDBGC(6);
453                  PDBGC_CLOSE;
454                  fcntl  (pfd, F_SETFD, FD_CLOEXEC);
455                  do {
456                    val_return = execve (pname, 
457                                         (task->argc == 0) ? argp : task->argv, 
458                                         (task->envc == 0) ? NULL : task->envv
459                                         );
460                  } while (val_return < 0 && errno == EINTR);
461                 
462                  errnum = errno;
463                  PDBGC_OPEN;
464                  PDBGC_S(strerror(errnum));
465                  PDBGC_S(task->command);
466                  PDBGC_S("fexecve: failed");
467                  PDBGC_CLOSE;
468                  /* failed
469                   */
470                  _exit((errnum == 0) ? (EXIT_SUCCESS) : (EXIT_FAILURE));
471              }
472              PDBGC_S("fexecve: not working");
473              /*
474               * procfs not working, go ahead; checksum is tested already
475               */
476              if (fd != -1)
477                sl_close(fd);
478              else if (pfd != -1)
479                sl_close_fd(FIL__, __LINE__, pfd);
480            }
481#endif
482
483          PDBGC_S(" -- non fexecve --");
484          /*
485           * --  execute path if executable
486           */
487          if (0 == access(task->command, R_OK|X_OK)) /* flawfinder: ignore */
488            {
489              PDBGC(5);
490              PDBGC_CLOSE;
491              do {
492                val_return = execve (task->command, 
493                                     (task->argc == 0) ? argp : task->argv, 
494                                     (task->envc == 0) ? envp : task->envv
495                                     );
496              } while (val_return < 0 && errno == EINTR);
497            }
498          errnum = errno;
499          PDBGC_OPEN;
500          PDBGC_S(strerror(errnum));
501          PDBGC_S(task->command);
502          PDBGC_S("execve: failed");
503          PDBGC_CLOSE;
504          /* failed
505           */
506          _exit((errnum == 0) ? (EXIT_SUCCESS) : (EXIT_FAILURE));
507        }
508      /*
509       * if we have forked twice, this is parent::detached_subprocess
510       */
511      if (S_TRUE == task->fork_twice)
512        {
513          _exit (0);
514        }
515    }
516
517 
518  /*
519   * -- parent; task->pid is child pid; exit status is status of
520   *    grandchild if exited
521   */
522  if (S_TRUE == task->fork_twice)
523    {
524      (void) waitpid (task->pid, NULL, 0);
525    }
526
527  PDBG(5);
528  /* open an output stream on top of the write side of the pipe
529   */
530  if (task->rw == 'w')
531    {
532      PDBG_S("is w");
533      (void) sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
534      (void) retry_fcntl (FIL__, __LINE__, pipedes[STDOUT_FILENO], 
535                          F_SETFD, FD_CLOEXEC);
536      outf = fdopen (pipedes[STDOUT_FILENO], "w");
537    }
538  else
539    {
540      PDBG_S("is r");
541      (void) sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
542      (void) retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], 
543                          F_SETFD, FD_CLOEXEC);
544      outf = fdopen (pipedes[STDIN_FILENO], "r");
545    }
546
547  if (outf == NULL) 
548    {
549      errnum = errno;
550      PDBG_S("outf == NULL");
551      tmp  = sh_util_safe_name (task->command);
552     
553      if (task->privileged == 0 && 0 == getuid())
554        sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_NOEXEC,
555                        (UID_CAST) task->run_user_uid, tmp);
556      else
557        sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_NOEXEC,
558                        (UID_CAST) getuid(), tmp);
559
560      SH_FREE(tmp);
561
562      (void) aud_kill (FIL__, __LINE__, task->pid, SIGKILL);
563      (void) sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
564      (void) sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
565      (void) waitpid (task->pid, NULL, 0);
566      task->pid = 0;
567
568      SL_RETURN ((-1), _("sh_ext_popen"));
569    }
570 
571  if (task->rw == 'w')
572    task->pipeFD   = pipedes[STDOUT_FILENO];
573  else
574    task->pipeFD   = pipedes[STDIN_FILENO];
575
576  PDBG_D(task->pipeFD);
577
578  task->pipeTI = sl_make_ticket(FIL__, __LINE__, task->pipeFD, _("pipe"), outf);
579
580  flags = (int) retry_fcntl (FIL__, __LINE__, task->pipeFD, F_GETFL, 0);
581  if (flags != (-1))
582    (void) retry_fcntl (FIL__, __LINE__, task->pipeFD, 
583                        F_SETFL, flags|O_NONBLOCK);
584  task->pipe     = outf;
585
586  PDBG_S("return from popen");
587  PDBG_CLOSE;
588 
589  SL_RETURN (0, _("sh_ext_popen"));
590}
591
592/*
593 * -- close the pipe
594 */
595extern int flag_err_debug;
596
597int sh_ext_pclose (sh_tas_t * task)
598{
599  int   status = 0;
600  int   retry  = 0;
601  pid_t retval;
602  char  infomsg[256];
603
604#ifdef WCONTINUED
605      int wflags = WNOHANG|WUNTRACED|WCONTINUED;
606#else
607      int wflags = WNOHANG|WUNTRACED;
608#endif
609
610  SL_ENTER(_("sh_ext_pclose"));
611
612  PDBG_OPEN;
613  PDBG_S(" -> pclose");
614  (void) fflush(task->pipe);
615  if (!SL_ISERROR(task->pipeTI))
616    (void) sl_close(task->pipeTI);
617
618  task->pipe     = NULL;
619  task->pipeFD   = (-1);
620  task->pipeTI   = SL_ETICKET;
621
622  if (S_FALSE == task->fork_twice)
623    {
624      infomsg[0] = '\0';
625
626    nochmal:
627      retval = waitpid(task->pid, &(task->exit_status), wflags);
628      /*@-bufferoverflowhigh@*/
629      if (task->pid == retval)
630        {
631#ifndef USE_UNO
632          if (WIFEXITED(task->exit_status) != 0)
633            {
634              task->exit_status = WEXITSTATUS(task->exit_status);
635              if ((flag_err_debug == S_TRUE) || (task->exit_status != 0))
636                sl_snprintf(infomsg, sizeof(infomsg),
637                            _("Subprocess exited normally with status %d"),
638                            task->exit_status);
639            }
640          else if (WIFSIGNALED(task->exit_status) != 0)
641            {
642              sl_snprintf(infomsg, sizeof(infomsg),
643                          _("Subprocess terminated by signal %d"),
644                          WTERMSIG(task->exit_status));
645              task->exit_status = EXIT_FAILURE;
646            }
647          else if (WIFSTOPPED(task->exit_status) != 0)
648            {
649              sl_snprintf(infomsg, sizeof(infomsg),
650                          _("Subprocess stopped by signal %d, killing"),
651                          WSTOPSIG(task->exit_status));
652              task->exit_status = EXIT_FAILURE;
653              (void) aud_kill (FIL__, __LINE__, task->pid, 9);
654              (void) retry_msleep (0, 30);
655              (void) waitpid (task->pid, NULL, wflags);
656            }
657          else
658            {
659              sl_snprintf(infomsg, sizeof(infomsg),
660                          _("Subprocess exit status unknown"));
661              task->exit_status = EXIT_FAILURE;
662            }
663#else
664          task->exit_status = EXIT_FAILURE;
665#endif
666        }
667      else if (0 == retval)
668        {
669          if (retry < 3)
670            {
671              ++retry;
672              (void) retry_msleep(0, (retry * 30));
673              goto nochmal;
674            }
675          (void) aud_kill (FIL__, __LINE__, task->pid, 9);
676          sl_snprintf(infomsg, sizeof(infomsg),
677                      _("Subprocess not yet exited, killing"));
678          task->exit_status = EXIT_FAILURE;
679          (void) waitpid (task->pid, NULL, 0);
680        }
681      else
682        {
683          sl_snprintf(infomsg, sizeof(infomsg),
684                      _("Waitpid returned error %d\n"), errno);
685          task->exit_status = EXIT_FAILURE;
686        }
687      /*@+bufferoverflowhigh@*/
688      status = task->exit_status;
689      if (flag_err_debug == S_TRUE)
690        {
691          sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, task->exit_status, 
692                          MSG_E_SUBGEN, infomsg, _("sh_ext_pclose"));
693        }
694      else if (status != 0)
695        {
696          sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, task->exit_status, 
697                          MSG_E_SUBGEN, infomsg, _("sh_ext_pclose"));
698        }
699    }
700
701  task->pid = 0;
702  task->exit_status = 0;
703  PDBG_S(" <--");
704  PDBG_CLOSE;
705  SL_RETURN (status, _("sh_ext_pclose"));
706}
707
708void sh_ext_tas_init (sh_tas_t * tas)
709{
710  int i;
711
712  tas->command       = NULL;
713  tas->argc          = 0;
714  tas->envc          = 0;
715  tas->checksum[0]   = '\0';
716  tas->pipeFD        = (-1);
717  tas->pipeTI        = SL_ETICKET;
718  tas->pid           = (pid_t) -1;
719  tas->privileged    = 1;
720  tas->pipe          = NULL;
721  tas->rw            = 'w';
722  tas->exit_status   = 0;
723  tas->fork_twice    = S_TRUE;
724
725  for (i = 0; i < 32; ++i)
726    {
727      tas->argv[i]          = NULL;
728      tas->envv[i]          = NULL;
729#if 0
730      tas->trusted_users[i] = (uid_t) -1;
731#endif
732    }
733
734  tas->run_user_uid     = (uid_t) getuid();
735  tas->run_user_gid     = (gid_t) getgid();
736
737  tas->com_fd = -1;
738  tas->com_ti = -1;
739  return;
740}
741
742
743int sh_ext_tas_add_envv(sh_tas_t * tas, const char * key, const char * val)
744{
745  size_t sk = 0, sv = 0;
746  int    si;
747
748  SL_ENTER(_("sh_ext_tas_add_envv"));
749
750  if (tas == NULL ||  (key == NULL      && val == NULL)      || 
751      tas->envc >= 30)
752    {
753      SL_RETURN (-1, _("sh_ext_tas_add_envv"));
754    }
755  if (key != NULL)
756    sk = strlen(key) + 1;
757  if (val != NULL)
758    sv = strlen(val) + 1;
759
760  if (!sl_ok_adds(sk, sv))
761    {
762      SL_RETURN (-1, _("sh_ext_tas_add_envv"));
763    }
764  si = tas->envc;
765  tas->envv[si] = SH_ALLOC(sk + sv);
766
767  if (key != NULL)
768    {
769      (void) sl_strlcpy(tas->envv[si], key, sk+sv);
770      (void) sl_strlcat(tas->envv[si], "=", sk+sv);
771      if (val != NULL)
772        (void) sl_strlcat(tas->envv[si], val, sk+sv);
773    }
774  else
775    (void) sl_strlcpy(tas->envv[si], val, sv);
776
777  ++(tas->envc);
778  SL_RETURN ((tas->envc), _("sh_ext_tas_add_envv"));
779}
780
781int sh_ext_tas_rm_argv(sh_tas_t * tas)
782{
783  int last;
784
785  SL_ENTER(_("sh_ext_tas_rm_argv"));
786  if (tas == NULL || tas->argc == 0)
787    {
788      SL_RETURN (-1, _("sh_ext_tas_rm_argv"));
789    }
790
791  last = (tas->argc - 1);
792  --(tas->argc);
793  SH_FREE(tas->argv[last]);
794  tas->argv[last] = NULL;
795  SL_RETURN ((tas->argc), _("sh_ext_tas_rm_argv"));
796}
797
798int sh_ext_tas_add_argv(sh_tas_t * tas, const char * val)
799{
800  size_t sv = 0;
801  int    si;
802
803  SL_ENTER(_("sh_ext_tas_add_argv"));
804
805  if (tas == NULL ||  val == NULL  || 
806      tas->argc >= 30)
807    {
808      SL_RETURN (-1, _("sh_ext_tas_add_argv"));
809    }
810
811  if (val != NULL)
812    sv = strlen(val) + 1;
813
814  si = tas->argc;
815  tas->argv[si] = SH_ALLOC(sv);
816
817  (void) sl_strlcpy(tas->argv[si], val, sv);
818
819  ++(tas->argc);
820  SL_RETURN ((tas->argc), _("sh_ext_tas_add_argv"));
821}
822
823void sh_ext_tas_command(sh_tas_t * tas, const char * command)
824{
825  size_t len = sl_strlen(command);
826  tas->command = SH_ALLOC(len+1);
827  (void) sl_strlcpy(tas->command, command, len+1);
828  return;
829}
830
831void sh_ext_tas_free(sh_tas_t * tas)
832{
833  int i;
834  if (NULL != tas->command)    SH_FREE(tas->command);
835 
836  for (i = 0; i < 32; ++i)
837    {
838      if (NULL != tas->argv[i])   SH_FREE(tas->argv[i]);
839      if (NULL != tas->envv[i])   SH_FREE(tas->envv[i]);
840    }
841
842  if (tas->com_ti != (-1))
843    {
844      (void) sl_close(tas->com_ti);
845      tas->com_ti = -1;
846      tas->com_fd = -1;
847    }
848
849  return;
850}
851
852static void task_init (sh_tas_t * task)
853{
854  sh_ext_tas_init(task);
855
856  (void) sh_ext_tas_add_envv (task, _("SHELL"), 
857                              _("/bin/sh")); 
858  (void) sh_ext_tas_add_envv (task, _("PATH"), 
859                              _("/sbin:/bin:/usr/sbin:/usr/bin:/usr/ucb")); 
860  (void) sh_ext_tas_add_envv (task, _("IFS"), " \n\t"); 
861
862  if (sh.timezone != NULL)
863    {
864      (void) sh_ext_tas_add_envv(task,  "TZ", sh.timezone);
865    }
866  return;
867}
868
869int sh_ext_popen_init (sh_tas_t * task, const char * command, char * argv0, ...)
870{
871  va_list vl;
872  int status;
873
874  task_init (task);
875 
876  if (!argv0)
877    {
878      sh_ext_tas_command(task,  _("/bin/sh"));
879
880      (void) sh_ext_tas_add_argv(task,  _("/bin/sh"));
881      (void) sh_ext_tas_add_argv(task,  _("-c"));
882      (void) sh_ext_tas_add_argv(task,  command);
883    }
884  else
885    {
886      char * s;
887
888      sh_ext_tas_command(task,  command);
889
890      (void) sh_ext_tas_add_argv(task, argv0);
891
892      va_start (vl, argv0);
893      s = va_arg (vl, char * );
894      while (s != NULL)
895        {
896          (void) sh_ext_tas_add_argv(task, s);
897          s = va_arg (vl, char * );
898        }
899      va_end (vl);
900
901    }
902  task->rw = 'r';
903  task->fork_twice = S_FALSE;
904
905  status = sh_ext_popen(task);
906
907  return status;
908}
909
910/* Execute a system command */
911
912int sh_ext_system (char * command, char * argv0, ...)
913{
914  sh_tas_t task;
915  int    status;
916  va_list vl;
917  char * s;
918
919  SL_ENTER(_("sh_ext_system"));
920
921  task_init (&task);
922 
923  sh_ext_tas_command(&task,  command);
924
925  (void) sh_ext_tas_add_argv(&task, argv0);
926 
927  va_start (vl, argv0);
928  s = va_arg (vl, char * );
929  while (s != NULL)
930    {
931      (void) sh_ext_tas_add_argv(&task, s);
932      s = va_arg (vl, char * );
933    }
934  va_end (vl);
935
936  task.rw = 'r';
937  task.fork_twice = S_FALSE;
938
939  status = sh_ext_popen(&task);
940
941  if (status != 0)
942    {
943      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_E_SUBGEN, 
944                      _("Could not execute command"), _("sh_ext_system"));
945      SL_RETURN ((-1), _("sh_ext_system"));
946    }
947
948  /* close pipe and return exit status
949   */
950  (void) sh_ext_pclose(&task);
951  sh_ext_tas_free (&task);
952  SL_RETURN ((status), _("sh_ext_system"));
953}
954
955/* Execute command, return first line of output
956 * ifconfig | grep -1 lo | tail -n 1 | sed s/.*inet addr:\([0-9.]*\)\(.*\)/\1/
957 */
958char * sh_ext_popen_str (const char * command)
959{
960  sh_tas_t task;
961  struct  sigaction  new_act;
962  struct  sigaction  old_act;
963  char * out = NULL;
964  int    status;
965
966  SL_ENTER(_("sh_ext_popen_str"));
967
968  status = sh_ext_popen_init (&task, command, NULL, NULL);
969
970  if (status != 0)
971    {
972      sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN, 
973                      _("Could not open pipe"), _("sh_ext_popen_str"));
974      SL_RETURN ((NULL), _("sh_ext_popen_str"));
975    }
976
977   /* ignore SIGPIPE (instead get EPIPE if connection is closed)
978    */
979   new_act.sa_handler = SIG_IGN;
980   new_act.sa_flags   = 0;
981   sigemptyset( &new_act.sa_mask );
982   
983   (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
984   
985  /* read from the open pipe
986   */
987  if (task.pipe != NULL)
988    {
989      int try = 1200; /* 1000 * 0.1 = 120 sec */
990      sh_string * s = sh_string_new(0);
991      do {
992        sh_string_read(s, task.pipe, 0);
993        if (sh_string_len(s) == 0)
994          {
995            --try; retry_msleep(0, 100);
996          }
997      } while (sh_string_len(s) == 0 && try != 0);
998
999      if (sh_string_len(s) == 0)
1000        {
1001          sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN, 
1002                          _("No output from command"), _("sh_ext_popen_str"));
1003        }
1004
1005      out = sh_util_strdup(sh_string_str(s));
1006      sh_string_destroy(&s);
1007    }
1008
1009  /* restore old signal handler
1010   */
1011  (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &old_act, NULL);
1012
1013  /* close pipe and return exit status
1014   */
1015  (void) sh_ext_pclose(&task);
1016  sh_ext_tas_free (&task);
1017  SL_RETURN ((out), _("sh_ext_popen_str"));
1018}
1019
1020
1021
1022
1023/* ---------------  EXTERN STUFF ------------------- */
1024
1025#if defined(WITH_EXTERNAL)
1026
1027typedef struct _sh_com_t
1028{
1029  char     type[4];
1030
1031  sh_filter_type * filter;
1032
1033  time_t   deadtime;
1034  time_t   last_run;
1035
1036  sh_tas_t tas;
1037
1038  struct _sh_com_t * next;
1039
1040} sh_com_t;
1041
1042
1043static
1044void set3 (char * pos, char c1, char c2, char c3)
1045{
1046  pos[0] = c1;
1047  pos[1] = c2;
1048  pos[2] = c3;
1049  pos[3] = '\0';
1050  return;
1051}
1052
1053
1054
1055/* initialize the external command structure
1056 */
1057static
1058sh_com_t * command_init(void)
1059{
1060  uid_t       ff_euid;
1061  sh_com_t  * ext_com = NULL;
1062
1063  SL_ENTER(_("command_init"));
1064
1065  ext_com = (sh_com_t *) SH_ALLOC(sizeof(sh_com_t));
1066
1067  if (!ext_com)
1068    {
1069      SL_RETURN( NULL, _("command_init"));
1070    }
1071
1072  sh_ext_tas_init (&(ext_com->tas));
1073
1074  (void) sl_get_euid(&ff_euid);
1075#if 0
1076  ext_com->tas.trusted_users[0] = (uid_t) 0;
1077  ext_com->tas.trusted_users[1] = (uid_t) (ff_euid);
1078#endif
1079
1080  /* ------------------------------------------------- */
1081
1082  set3(ext_com->type, 'l', 'o', 'g');
1083  ext_com->filter       = NULL;
1084  ext_com->deadtime     = 0;
1085  ext_com->last_run     = 0;
1086
1087  ext_com->next             = NULL;
1088
1089  SL_RETURN( ext_com, _("command_init"));
1090}
1091
1092/* the list of external commands
1093 */
1094static sh_com_t * ext_coms   = NULL;
1095
1096/* if -1, allocation of last command has failed,
1097 * thus don't fill in options
1098 */
1099static int ext_failed = -1;
1100
1101static
1102int sh_ext_add_envv(const char * key, const char * val)
1103{
1104  int retval; 
1105
1106  SL_ENTER(_("sh_ext_add_envv"));
1107
1108  if (ext_coms == NULL || ext_failed == (-1) || 
1109      (key == NULL      && val == NULL)      || 
1110      ext_coms->tas.envc >= 30)
1111    {
1112      SL_RETURN (-1, _("sh_ext_add_envv"));
1113    }
1114
1115  retval = sh_ext_tas_add_envv(&(ext_coms->tas), key, val);
1116
1117  if (retval >= 0) 
1118    retval = 0;
1119
1120  SL_RETURN (retval, _("sh_ext_add_envv"));
1121}
1122
1123
1124
1125static 
1126int sh_ext_init(const char * command)
1127{
1128  sh_com_t * retval;
1129  size_t     size;
1130
1131  SL_ENTER(_("sh_ext_init"));
1132
1133  if (command == NULL)
1134    {
1135      SL_RETURN (-1, _("sh_ext_init"));
1136    }
1137  size = strlen(command);
1138  if (command[0] != '/' || size < 2)
1139    {
1140      SL_RETURN (-1, _("sh_ext_init"));
1141    }
1142
1143  if (NULL == (retval = command_init()))
1144    {
1145      SL_RETURN (-1, _("sh_ext_init"));
1146    }
1147
1148  sh_ext_tas_command(&(retval->tas), command);
1149
1150  if (sh.timezone != NULL)
1151    {
1152      (void) sh_ext_add_envv( "TZ", sh.timezone);
1153    }
1154
1155  retval->next = ext_coms;
1156  ext_coms     = retval;
1157  SL_RETURN (0, _("sh_ext_init"));
1158}
1159
1160static
1161int sh_ext_uid (const char * user, /*@out@*/uid_t * uid, /*@out@*/gid_t * gid)
1162{
1163  struct passwd *  tempres;
1164#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1165  struct passwd    pwd;
1166  char           * buffer = SH_ALLOC(SH_PWBUF_SIZE);
1167#endif
1168
1169  SL_ENTER(_("sh_ext_uid"));
1170
1171  *uid = (uid_t)-1; *gid = (gid_t)-1;
1172
1173  if (user == NULL)
1174    {
1175#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1176      SH_FREE(buffer);
1177#endif
1178      SL_RETURN (-1, _("sh_ext_uid"));
1179    }
1180
1181#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1182  sh_getpwnam_r(user, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
1183#else
1184  tempres = sh_getpwnam(user);
1185#endif
1186
1187  if (NULL != tempres) 
1188    {
1189      *uid = tempres->pw_uid; 
1190      *gid = tempres->pw_gid;
1191#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1192      SH_FREE(buffer);
1193#endif
1194      SL_RETURN (0, _("sh_ext_uid"));
1195    } 
1196
1197#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1198  SH_FREE(buffer);
1199#endif
1200  SL_RETURN (-1, _("sh_ext_uid"));
1201}
1202
1203
1204static
1205int sh_ext_add (const char * argstring, int * ntok, char * stok[])
1206{
1207  int    i = 0;
1208  size_t s;
1209  char * p;
1210  char * new;
1211  size_t len;
1212
1213  SL_ENTER(_("sh_ext_add"));
1214
1215  if (NULL == argstring)
1216    {
1217      SL_RETURN((-1), _("sh_ext_add")); 
1218    }
1219
1220  len = strlen(argstring) + 1;
1221  new = SH_ALLOC(len);
1222  sl_strlcpy(new, argstring, len); 
1223
1224  do
1225    {
1226#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
1227      char * saveptr;
1228      if (i == 0)
1229        p = strtok_r (new, ", \t", &saveptr);
1230      else
1231        p = strtok_r (NULL, ", \t", &saveptr);
1232#else
1233      if (i == 0)
1234        p = strtok (new, ", \t");
1235      else
1236        p = strtok (NULL, ", \t");
1237#endif
1238
1239      if (p == NULL)
1240        break;
1241
1242      s = strlen(p) + 1;
1243      if (stok[i] != NULL)
1244        SH_FREE(stok[i]);
1245      stok[i] = SH_ALLOC(s);
1246      (void) sl_strlcpy(stok[i], p, s);
1247
1248      ++i;
1249      if (i == 30)
1250        break;
1251    }
1252  while (p != NULL);
1253
1254  *ntok = i;
1255  SH_FREE(new);
1256
1257  SL_RETURN (0, _("sh_ext_add"));
1258}
1259
1260/*********************************************************
1261 *
1262 * Public functions
1263 *
1264 *
1265 *********************************************************/
1266 
1267/*
1268 * -- start a new external command, and add it to the list
1269 */ 
1270int sh_ext_setcommand(const char * cmd)
1271{
1272  int i;
1273
1274  SL_ENTER(_("sh_ext_setcommand"));
1275  if ( (i = sh_ext_init(cmd)) < 0)
1276    ext_failed = -1;
1277  else
1278    ext_failed = 0;
1279  SL_RETURN( i, _("sh_ext_setcommand"));
1280}
1281
1282
1283/*
1284 * -- clean up the command list
1285 */
1286int sh_ext_cleanup(void)
1287{
1288  sh_com_t * retval;
1289
1290  SL_ENTER(_("sh_ext_cleanup"));
1291
1292  while (ext_coms != NULL)
1293    {
1294      retval   = ext_coms;
1295      ext_coms = retval->next;
1296
1297      sh_ext_tas_free (&(retval->tas));
1298
1299      if (retval->filter)
1300        sh_filter_free (retval->filter);
1301
1302      SH_FREE(retval);
1303
1304    }
1305
1306  SL_RETURN (0, _("sh_ext_cleanup"));
1307}
1308
1309/*
1310 * -- explicitely close a command
1311 */
1312int sh_ext_close_command (const char * str)
1313{
1314  (void) str;
1315  if (ext_coms == NULL || ext_failed == (-1))
1316    return (-1);
1317  ext_failed = (-1);
1318  return 0;
1319}
1320
1321/*
1322 * -- add keywords to the OR filter
1323 */
1324int sh_ext_add_or (const char * str)
1325{
1326  if (ext_coms == NULL || ext_failed == (-1))
1327    return (-1);
1328  if (ext_coms->filter == NULL)
1329    ext_coms->filter = sh_filter_alloc();
1330  return (sh_filter_add(str, ext_coms->filter, SH_FILT_OR));
1331}
1332
1333/*
1334 * -- add keywords to the AND filter
1335 */
1336int sh_ext_add_and (const char * str)
1337{
1338  if (ext_coms == NULL || ext_failed == (-1))
1339    return (-1);
1340  if (ext_coms->filter == NULL)
1341    ext_coms->filter = sh_filter_alloc();
1342  return (sh_filter_add(str, ext_coms->filter, SH_FILT_AND));
1343}
1344
1345/*
1346 * -- add keywords to the NOT filter
1347 */
1348int sh_ext_add_not (const char * str)
1349{
1350  if (ext_coms == NULL || ext_failed == (-1))
1351    return (-1);
1352  if (ext_coms->filter == NULL)
1353    ext_coms->filter = sh_filter_alloc();
1354  return (sh_filter_add(str, ext_coms->filter, SH_FILT_NOT));
1355}
1356
1357/*
1358 * -- add keywords to the CL argument list
1359 */
1360int sh_ext_add_argv (const char * str)
1361{
1362  if (ext_coms == NULL || ext_failed == (-1))
1363    return (-1);
1364  return (sh_ext_add (str, &(ext_coms->tas.argc), ext_coms->tas.argv));
1365}
1366
1367/*
1368 * -- add a path to the environment
1369 */
1370int sh_ext_add_default (const char * dummy)
1371{
1372  char * p = NULL;
1373  int    i;
1374  char   dir[SH_PATHBUF];
1375
1376  SL_ENTER(_("sh_ext_add_default"));
1377  if (dummy[0] == 'n' ||  dummy[0] == 'N' ||
1378      dummy[0] == 'f' ||  dummy[0] == 'F' || dummy[0] == '0')
1379    {
1380      SL_RETURN(0, _("sh_ext_add_default"));
1381    }
1382  p = sh_unix_getUIDdir (SH_ERR_ERR, (uid_t) ext_coms->tas.run_user_uid, 
1383                         dir, sizeof(dir));
1384  if (p)
1385    (void) sh_ext_add_envv (_("HOME"), p);
1386  (void) sh_ext_add_envv (_("SHELL"), _("/bin/sh")); 
1387  (void) sh_ext_add_envv (_("PATH"),  _("/sbin:/bin:/usr/sbin:/usr/bin")); 
1388  (void) sh_ext_add_envv (_("IFS"), " \n\t"); 
1389  i = (p == NULL ? (-1) :  0);
1390  SL_RETURN(i, _("sh_ext_add_default"));
1391}
1392
1393/*
1394 * -- add an environment variable
1395 */
1396int sh_ext_add_environ (const char * str)
1397{
1398  int i;
1399
1400  SL_ENTER(_("sh_ext_add_environ"));
1401  i = sh_ext_add_envv (NULL, str);
1402  SL_RETURN(i, _("sh_ext_add_environ"));
1403}
1404
1405/*
1406 * -- set deadtime
1407 */
1408int sh_ext_deadtime (const char * str)
1409{
1410  long    deadtime = 0;
1411  char  * tail     = NULL;
1412
1413  SL_ENTER(_("sh_ext_deadtime"));
1414
1415  if (ext_coms == NULL || ext_failed == (-1) || str == NULL)
1416    {
1417      SL_RETURN (-1, _("sh_ext_deadtime"));
1418    }
1419  deadtime = strtol(str, &tail, 10);
1420  if (tail == str || deadtime < 0 || deadtime == LONG_MAX)
1421    {
1422      SL_RETURN (-1, _("sh_ext_deadtime"));
1423    }
1424 
1425  ext_coms->deadtime = (time_t) deadtime; 
1426  SL_RETURN (0, _("sh_ext_deadtime")); 
1427}
1428
1429/*
1430 * -- define type
1431 */
1432int sh_ext_type (const char * str)
1433{
1434  SL_ENTER(_("sh_ext_type"));
1435
1436  if (ext_coms == NULL || ext_failed == (-1) || str == NULL)
1437    {
1438      SL_RETURN((-1), _("sh_ext_type"));
1439    }
1440
1441  if (strlen(str) != 3)
1442    {
1443      SL_RETURN((-1), _("sh_ext_type"));
1444    }
1445
1446  set3(ext_coms->type, str[0], str[1], str[2]);
1447
1448  if      (str[0] == 'l' && str[1] == 'o' && str[2] == 'g')
1449    ext_coms->tas.rw = 'w';
1450  else if (str[0] == 's' && str[1] == 'r' && str[2] == 'v')
1451    ext_coms->tas.rw = 'w';
1452  else if (str[0] == 'm' && str[1] == 'o' && str[2] == 'n')
1453    ext_coms->tas.rw = 'r';
1454  else
1455    {
1456      SL_RETURN((-1), _("sh_ext_type"));
1457    }
1458
1459  SL_RETURN(0, _("sh_ext_type"));
1460} 
1461 
1462
1463
1464/*
1465 * -- define checksum
1466 */
1467int sh_ext_checksum (const char * str)
1468{
1469  SL_ENTER(_("sh_ext_checksum"));
1470  if (ext_coms == NULL || ext_failed == (-1) || str == NULL)
1471    {
1472      SL_RETURN((-1), _("sh_ext_checksum"));
1473    }
1474
1475  if (sl_strlen(str) != KEY_LEN)
1476    {
1477      SL_RETURN((-1), _("sh_ext_checksum"));
1478    }
1479
1480  (void) sl_strlcpy (ext_coms->tas.checksum, str, KEY_LEN+1);
1481
1482  SL_RETURN((0), _("sh_ext_checksum"));
1483}
1484
1485/*
1486 * -- choose privileges
1487 */
1488int sh_ext_priv (const char * c)
1489{
1490
1491  uid_t me_uid;
1492  gid_t me_gid;
1493
1494  SL_ENTER(_("sh_ext_priv"));
1495  if (0 == sh_ext_uid (c, &me_uid, &me_gid))
1496    {
1497      ext_coms->tas.run_user_uid = me_uid;
1498      ext_coms->tas.run_user_gid = me_gid;
1499      if (me_uid != (uid_t) 0)
1500        ext_coms->tas.privileged   = 0;
1501      SL_RETURN((0), _("sh_ext_priv"));
1502    }
1503
1504  SL_RETURN (-1, _("sh_ext_priv"));
1505}
1506
1507
1508
1509
1510/*
1511 * -- check filters
1512 */
1513static int sh_ext_filter (char * message, sh_com_t * task)
1514{
1515  time_t now_time;
1516
1517  SL_ENTER(_("sh_ext_filter"));
1518
1519  if (task->filter)
1520    {
1521      if (0 != sh_filter_filter (message, task->filter))
1522        {
1523          SL_RETURN ((-1), _("sh_ext_filter"));
1524        }
1525    }
1526
1527  /* Filter passed, check deadtime */
1528
1529  if (task->deadtime != (time_t) 0)
1530    {
1531      now_time = time (NULL);
1532     
1533      if (task->last_run == (time_t) 0)
1534        {
1535          task->last_run = now_time;
1536        }
1537      else if ((time_t)(now_time-task->last_run) < task->deadtime)
1538        {
1539          SL_RETURN ((-1), _("sh_ext_filter"));
1540        }
1541      else
1542        {
1543          task->last_run = now_time;
1544        }
1545    }
1546
1547  SL_RETURN ((0), _("sh_ext_filter"));
1548}
1549
1550
1551
1552/*
1553 * -- execute external script/program
1554 */
1555int sh_ext_execute (char t1, char t2, char t3, /*@null@*/char * message, 
1556                    size_t msg_siz)
1557{
1558  int        caperr;
1559  sh_com_t * listval = ext_coms;
1560  int        status = 0;
1561  char     * tmp;
1562  char errbuf[SH_ERRBUF_SIZE];
1563
1564  static  int some_error = 0;
1565
1566  struct  sigaction  new_act;
1567  struct  sigaction  old_act;
1568
1569  SL_ENTER(_("sh_ext_execute"));
1570
1571  PDBG_OPEN;
1572
1573  if (listval == NULL || message == NULL)
1574    {
1575      SL_RETURN ((-1), _("sh_ext_execute"));
1576    }
1577
1578  PDBG(-1);
1579
1580  if (msg_siz == 0)
1581    msg_siz = sl_strlen(message);
1582
1583
1584  /* ignore SIGPIPE (instead get EPIPE if connection is closed)
1585   */
1586  new_act.sa_handler = SIG_IGN;
1587  (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
1588
1589  while (listval != NULL)
1590    {
1591      PDBG_OPEN;
1592      PDBG(-2);
1593      if (t1 == listval->type[0] &&
1594          t2 == listval->type[1] &&
1595          t3 == listval->type[2] &&
1596          0 == sh_ext_filter (message, listval))
1597        {
1598          PDBG(-3);
1599
1600          if (0 != (caperr = sl_get_cap_sub()))
1601            {
1602              sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
1603                              sh_error_message (caperr, errbuf, sizeof(errbuf)), 
1604                              _("sl_get_cap_sub"));
1605            }
1606          if (0 == sh_ext_popen (&(listval->tas)))
1607            {
1608              PDBG_OPEN;
1609              PDBG(-4);
1610              if (NULL != listval->tas.pipe && listval->tas.rw == 'w')
1611                {
1612                  PDBG(-5);
1613                  if (message != NULL)
1614                    {
1615                      PDBG(-6);
1616                      status = (int) write (listval->tas.pipeFD, 
1617                                            message, msg_siz);
1618                      if (status >= 0)
1619                        status = (int) write (listval->tas.pipeFD, "\n", 1);
1620                    }
1621                  PDBG_D(status);
1622                  if (status >= 0)
1623                    status = (int) write (listval->tas.pipeFD, "[", 1);
1624                  PDBG_D(status);
1625                  if (status >= 0)
1626                    status = (int) write (listval->tas.pipeFD, "E", 1);
1627                  PDBG_D(status);
1628                  if (status >= 0)
1629                    status = (int) write (listval->tas.pipeFD, "O", 1);
1630                  PDBG_D(status);
1631                  if (status >= 0)
1632                    status = (int) write (listval->tas.pipeFD, "F", 1);
1633                  PDBG_D(status);
1634                  if (status >= 0)
1635                    status = (int) write (listval->tas.pipeFD, "]", 1);
1636                  PDBG_D(status);
1637                  if (status >= 0)
1638                    status = (int) write (listval->tas.pipeFD, "\n", 1);
1639                  PDBG_D(status);
1640                  if (status >= 0)
1641                    {
1642                      some_error = 0;
1643                    }
1644                  if ((status < 0) && (some_error == 0))
1645                    {
1646                      some_error = 1;
1647                      PDBG_S("some error");
1648                      PDBG_D(status);
1649                      tmp  = sh_util_safe_name (listval->tas.command);
1650
1651                      if (tmp)
1652                        {
1653                          if (listval->tas.privileged == 0 && 
1654                              (0 == getuid() || 0 != sl_is_suid()) )
1655                            sh_error_handle((-1), FIL__, __LINE__, 0, 
1656                                            MSG_NOEXEC,
1657                                            (UID_CAST) listval->tas.run_user_uid, 
1658                                            tmp);
1659                          else
1660                            sh_error_handle((-1), FIL__, __LINE__, 0, 
1661                                            MSG_NOEXEC,
1662                                            (UID_CAST) getuid(), tmp);
1663                         
1664                          SH_FREE(tmp);
1665                        }
1666
1667                    } 
1668                  PDBG(-7);
1669                  (void) fflush(listval->tas.pipe);
1670                }
1671              PDBG(-8);
1672              (void) sh_ext_pclose(&(listval->tas));
1673            }
1674          else
1675            {
1676              PDBG_OPEN;
1677              PDBG_S("0 != sh_ext_popen()");
1678            }
1679          if (0 != (caperr = sl_drop_cap_sub()))
1680            {
1681              sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
1682                              sh_error_message (caperr, errbuf, sizeof(errbuf)), 
1683                              _("sl_drop_cap_sub"));
1684            }
1685
1686        }
1687      listval = listval->next;
1688    }
1689  PDBG_OPEN;
1690  PDBG_S("no more commands");
1691
1692  /* restore old signal handler
1693   */
1694  (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &old_act, NULL);
1695  PDBG_S("return");
1696  PDBG_CLOSE;
1697
1698  SL_RETURN ((0), _("sh_ext_execute"));
1699}
1700 
1701 
1702/* #if defined(WITH_EXTERNAL) */
1703#endif
Note: See TracBrowser for help on using the repository browser.