source: trunk/src/sh_extern.c@ 483

Last change on this file since 483 was 481, checked in by katerina, 9 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

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