source: trunk/src/sh_extern.c@ 249

Last change on this file since 249 was 248, checked in by katerina, 15 years ago

Code to track down originating site for ticket #163.

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