source: trunk/src/sh_extern.c@ 247

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

Fix a race condition that might have caused ticket #163.

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