source: trunk/src/sh_extern.c@ 406

Last change on this file since 406 was 400, checked in by katerina, 13 years ago

Fix for ticket #297 (Potential deadlock in sh_ext_popen).

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