source: trunk/src/sh_suidchk.c@ 131

Last change on this file since 131 was 131, checked in by rainer, 17 years ago

Use thread-safe libc functions.

File size: 50.4 KB
RevLine 
[1]1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2001 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#include "config_xor.h"
21
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <errno.h>
31#include <limits.h>
[94]32
[1]33#ifdef HAVE_SCHED_H
34#include <sched.h>
35#endif
36
37#ifdef SH_USE_SUIDCHK
38
39#undef FIL__
40#define FIL__ _("sh_suidchk.c")
41
42#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
43
44#if TIME_WITH_SYS_TIME
45#include <sys/time.h>
46#include <time.h>
47#else
48#if HAVE_SYS_TIME_H
49#include <sys/time.h>
50#else
51#include <time.h>
52#endif
53#endif
54
55#ifdef HAVE_DIRENT_H
56#include <dirent.h>
57#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
58#else
59#define dirent direct
60#define NAMLEN(dirent) (dirent)->d_namlen
61#ifdef HAVE_SYS_NDIR_H
62#include <sys/ndir.h>
63#endif
64#ifdef HAVE_SYS_DIR_H
65#include <sys/dir.h>
66#endif
67#ifdef HAVE_NDIR_H
68#include <ndir.h>
69#endif
70#endif
71
72#include "samhain.h"
[131]73#include "sh_pthread.h"
[1]74#include "sh_utils.h"
75#include "sh_error.h"
76#include "sh_modules.h"
77#include "sh_suidchk.h"
78#include "sh_hash.h"
79#include "sh_unix.h"
80#include "sh_files.h"
81#include "sh_schedule.h"
82#include "sh_calls.h"
83
84
85sh_rconf sh_suidchk_table[] = {
86 {
87 N_("severitysuidcheck"),
88 sh_suidchk_set_severity
89 },
90 {
91 N_("suidcheckactive"),
92 sh_suidchk_set_activate
93 },
94 {
95 N_("suidcheckinterval"),
96 sh_suidchk_set_timer
97 },
98 {
99 N_("suidcheckschedule"),
100 sh_suidchk_set_schedule
101 },
102 {
103 N_("suidcheckexclude"),
104 sh_suidchk_set_exclude
105 },
106 {
107 N_("suidcheckfps"),
108 sh_suidchk_set_fps
109 },
110 {
111 N_("suidcheckyield"),
112 sh_suidchk_set_yield
113 },
114 {
[119]115 N_("suidchecknosuid"),
116 sh_suidchk_set_nosuid
117 },
118 {
[1]119 N_("suidcheckquarantinefiles"),
120 sh_suidchk_set_quarantine
121 },
122 {
123 N_("suidcheckquarantinemethod"),
124 sh_suidchk_set_qmethod
125 },
126 {
127 N_("suidcheckquarantinedelete"),
128 sh_suidchk_set_qdelete
129 },
130 {
131 NULL,
132 NULL
133 },
134};
135
136
137static time_t lastcheck = (time_t) 0;
138static int ShSuidchkActive = S_TRUE;
139static time_t ShSuidchkInterval = 7200;
140static long ShSuidchkFps = 0;
[119]141static int ShSuidchkNosuid = S_FALSE;
[1]142static int ShSuidchkYield = S_FALSE;
143static int ShSuidchkQEnable = S_FALSE;
144static int ShSuidchkQMethod = SH_Q_CHANGEPERM;
145static int ShSuidchkQDelete = S_FALSE;
146static int ShSuidchkSeverity = SH_ERR_SEVERE;
147static char * ShSuidchkExclude = NULL;
[68]148static size_t ExcludeLen = 0;
[1]149
150static time_t FileLimNow = 0;
151static time_t FileLimStart = 0;
152static long FileLimNum = 0;
153static long FileLimTotal = 0;
154
155static sh_schedule_t * ShSuidchkSched = NULL;
156
157static char *
158filesystem_type (char * path, char * relpath, struct stat * statp);
159
160#ifndef PATH_MAX
161#define PATH_MAX 1024
162#endif
163
164extern unsigned long sh_files_maskof (int class);
165
166/* Recursively descend into the directory to make sure that
167 * there is no symlink in the path.
168 */
169static int do_truncate_int (char * path, int depth)
170{
171 char * q;
172 struct stat one;
173 struct stat two;
174 int fd;
175
176 if (depth > 99)
177 {
178 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
179 MSG_SUID_ERROR,
180 _("do_truncate: max depth 99 exceeded"));
181 return -1;
182 }
183 ++depth;
184 if (path[0] != '/')
185 {
186 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
187 MSG_SUID_ERROR,
188 _("do_truncate: not an absolute path"));
189 return -1;
190 }
191 ++path;
192 q = strchr(path, '/');
193 if (q)
194 {
195 *q = '\0';
196 if (0 != retry_lstat(FIL__, __LINE__, path, &one))
197 {
198 sh_error_handle ((-1), FIL__, __LINE__, errno,
199 MSG_SUID_ERROR,
200 sh_error_message(errno));
201 *q = '/';
202 return -1;
203 }
204 if (/*@-usedef@*/!S_ISDIR(one.st_mode)/*@+usedef@*/)
205
206 {
207 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
208 MSG_SUID_ERROR,
209 _("Possible race: not a directory"));
210 *q = '/';
211 return -1;
212 }
213
214
215 if (0 != chdir(path))
216 {
217 sh_error_handle ((-1), FIL__, __LINE__, errno,
218 MSG_SUID_ERROR,
219 sh_error_message(errno));
220 *q = '/';
221 return -1;
222 }
223 *q = '/';
224 if (0 != retry_lstat(FIL__, __LINE__, ".", &two))
225 {
226 sh_error_handle ((-1), FIL__, __LINE__, errno,
227 MSG_SUID_ERROR,
228 sh_error_message(errno));
229 return -1;
230 }
231 if (/*@-usedef@*/(one.st_dev != two.st_dev) ||
232 (one.st_ino != two.st_ino) ||
233 (!S_ISDIR(two.st_mode))/*@+usedef@*/)
234 {
235 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
236 MSG_SUID_ERROR,
237 _("Possible race: lstat(dir) != lstat(.)"));
238 return -1;
239 }
240
241
242 return (do_truncate_int(q, depth));
243 }
244 else
245 {
246 /* no more '/', so this is the file
247 */
248 if (*path == '\0')
249 return -1;
250 if (0 != retry_lstat(FIL__, __LINE__, path, &one))
251 {
252 sh_error_handle ((-1), FIL__, __LINE__, errno,
253 MSG_SUID_ERROR,
254 sh_error_message(errno));
255 return -1;
256 }
257 fd = open(path, O_RDWR);
258 if (-1 == fd)
259 {
260 sh_error_handle ((-1), FIL__, __LINE__, errno,
261 MSG_SUID_ERROR,
262 sh_error_message(errno));
263 return -1;
264 }
265 if (0 != retry_fstat(FIL__, __LINE__, fd, &two))
266 {
267 sh_error_handle ((-1), FIL__, __LINE__, errno,
268 MSG_SUID_ERROR,
269 sh_error_message(errno));
270 (void) close(fd);
271 return -1;
272 }
273 if (/*@-usedef@*/(one.st_dev != two.st_dev) ||
274 (one.st_ino != two.st_ino)/*@+usedef@*/)
275 {
276 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
277 MSG_SUID_ERROR,
278 _("Possible race: lstat != fstat"));
279 (void) close(fd);
280 return -1;
281 }
282 if (!S_ISREG(two.st_mode))
283 {
284 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
285 MSG_SUID_ERROR,
286 _("Possible race: not a regular file"));
287 (void) close(fd);
288 return -1;
289 }
290 if ((0 == (two.st_mode & S_ISUID)) && (0 == (two.st_mode & S_ISGID)))
291 {
292 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
293 MSG_SUID_ERROR,
294 _("Possible race: not a suid/sgid file"));
295 (void) close(fd);
296 return -1;
297 }
298 if (ShSuidchkQDelete == S_FALSE)
299 {
300 if ((two.st_mode & S_ISUID) > 0)
301 two.st_mode -= S_ISUID;
302 if ((two.st_mode & S_ISGID) > 0)
303 two.st_mode -= S_ISGID;
304#ifdef HAVE_FCHMOD
305 if (-1 == /*@-unrecog@*/fchmod(fd, two.st_mode)/*@+unrecog@*/)
306 {
307 sh_error_handle ((-1), FIL__, __LINE__, errno,
308 MSG_SUID_ERROR,
309 sh_error_message(errno));
310 (void) close(fd);
311 return -1;
312 }
313#else
314 sh_error_handle ((-1), FIL__, __LINE__, errno,
315 MSG_SUID_ERROR,
316 _("The fchmod() function is not available"));
317 (void) close(fd);
318 return -1;
319#endif
320 if (two.st_nlink > 1)
321 {
322 sh_error_handle ((-1), FIL__, __LINE__, 0,
323 MSG_SUID_ERROR,
324 _("Not truncated because hardlink count gt 1"));
325 (void) close(fd);
326 return -1;
327 }
328 /* The man page says: 'POSIX has ftruncate'
329 */
330 if (-1 == /*@-unrecog@*/ftruncate(fd, 0)/*@+unrecog@*/)
331 {
332 sh_error_handle ((-1), FIL__, __LINE__, errno,
333 MSG_SUID_ERROR,
334 sh_error_message(errno));
335 (void) close(fd);
336 return -1;
337 }
338 }
339 else
340 {
341 if (-1 == retry_aud_unlink(FIL__, __LINE__, path))
342 {
343 sh_error_handle ((-1), FIL__, __LINE__, errno,
344 MSG_SUID_ERROR,
345 sh_error_message(errno));
346 (void) close(fd);
347 return -1;
348 }
349 }
350 (void) close (fd);
351 return (0);
352 }
353}
354
[94]355static int do_truncate (const char * path_in)
[1]356{
[94]357 int caperr;
358 int result;
359 char * path;
[1]360
361 if (0 != chdir("/"))
362 {
363 sh_error_handle ((-1), FIL__, __LINE__, errno,
364 MSG_SUID_ERROR,
365 sh_error_message(errno));
366 }
367
368 if (0 != (caperr = sl_get_cap_qdel()))
369 {
370 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
371 sh_error_message (caperr),
372 _("sl_get_cap_qdel"));
373 }
374
[94]375 path = sh_util_strdup (path_in);
[1]376 result = do_truncate_int (path, 0);
[94]377 SH_FREE(path);
[1]378
379 if (0 != (caperr = sl_drop_cap_qdel()))
380 {
381 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
382 sh_error_message (caperr),
383 _("sl_drop_cap_qdel"));
384 }
385
386 if (0 != chdir("/"))
387 {
388 sh_error_handle ((-1), FIL__, __LINE__, errno,
389 MSG_SUID_ERROR,
390 sh_error_message(errno));
391 }
392 return result;
393}
394
[94]395static void sh_q_delete(const char * fullpath)
396{
397 int status;
398 char * msg;
399 char * tmp;
400
401 if (do_truncate (fullpath) == -1)
402 {
403 status = errno;
404 msg = SH_ALLOC(SH_BUFSIZE);
405 tmp = sh_util_safe_name(fullpath);
406
407 (void) sl_snprintf(msg, SH_BUFSIZE,
408 _("Problem quarantining file. File NOT quarantined. errno = %ld"),
409 status);
410 sh_error_handle (ShSuidchkSeverity,
411 FIL__, __LINE__,
412 status,
413 MSG_SUID_QREPORT, msg,
414 tmp );
415 SH_FREE(tmp);
416 SH_FREE(msg);
417 }
418 else
419 {
420 tmp = sh_util_safe_name(fullpath);
421 sh_error_handle (ShSuidchkSeverity,
422 FIL__, __LINE__, 0,
423 MSG_SUID_QREPORT,
424 _("Quarantine method applied"),
425 tmp );
426 SH_FREE(tmp);
427 }
428 return;
429}
430
431static void sh_q_move(const char * fullpath, file_type * theFile,
432 const char * timestrc, const char * timestra,
433 const char * timestrm)
434{
435 int status;
436 int readFile = -1;
437 int writeFile = -1;;
438 struct stat fileInfo;
439 ssize_t count;
440 char * msg;
441 char * tmp;
442 char * basetmp;
443 char * filetmp;
444 char buffer[1024];
445 char * dir = SH_ALLOC(PATH_MAX+1);
446 mode_t umask_old;
447 FILE * filePtr = NULL;
448
449 (void) sl_strlcpy (dir, DEFAULT_QDIR, PATH_MAX+1);
450
451 if (retry_stat (FIL__, __LINE__, dir, &fileInfo) != 0)
452 {
453 /* Quarantine directory does not exist,
454 */
455 status = errno;
456 msg = SH_ALLOC(SH_BUFSIZE);
457 tmp = sh_util_safe_name(fullpath);
458
459 (void) sl_snprintf(msg, SH_BUFSIZE,
460 _("Problem quarantining file. File NOT quarantined. errno = %ld (stat)"),
461 status);
462 sh_error_handle (ShSuidchkSeverity,
463 FIL__, __LINE__,
464 status,
465 MSG_SUID_QREPORT, msg,
466 tmp );
467 SH_FREE(tmp);
468 SH_FREE(msg);
469 }
470 else
471 {
472 if (retry_lstat (FIL__, __LINE__,
473 fullpath, &fileInfo) == -1)
474 {
475 status = errno;
476 msg = SH_ALLOC(SH_BUFSIZE);
477 tmp = sh_util_safe_name(fullpath);
478
479 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld(stat)"), status);
480 sh_error_handle (ShSuidchkSeverity,
481 FIL__, __LINE__,
482 status,
483 MSG_SUID_QREPORT,
484 msg, tmp );
485 SH_FREE(tmp);
486 SH_FREE(msg);
487 }
488 else
489 {
490 basetmp = sh_util_strdup(fullpath);
491 filetmp = SH_ALLOC(PATH_MAX+1);
492 tmp = sh_util_basename(basetmp);
493
494 (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s",
495 DEFAULT_QDIR, tmp);
496 SH_FREE(tmp);
497 SH_FREE(basetmp);
498
499 readFile = open (fullpath, O_RDONLY);
500 if (readFile != -1)
501 writeFile = open (filetmp, O_WRONLY|O_CREAT);
502
503 if ((readFile == -1) || (writeFile == -1))
504 {
505 status = errno;
506 msg = SH_ALLOC(SH_BUFSIZE);
507 tmp = sh_util_safe_name(fullpath);
508
509 (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld (open)"), status);
510 sh_error_handle (ShSuidchkSeverity,
511 FIL__, __LINE__, status,
512 MSG_SUID_QREPORT,
513 msg, tmp );
514 SH_FREE(tmp);
515 SH_FREE(msg);
516 }
517 else
518 {
519 /* sizeof(buffer) is 1024
520 */
521 while ((count = (int) read (readFile, buffer, sizeof (buffer))) > 0)
522 {
523 if ((int) write (writeFile, buffer, (size_t) count) != count)
524 {
525 status = errno;
526 msg = SH_ALLOC(SH_BUFSIZE);
527 tmp = sh_util_safe_name(fullpath);
528
529 (void) sl_snprintf(msg, SH_BUFSIZE,
530 _("I/O error. errno = %ld (write)"), status);
531 sh_error_handle (ShSuidchkSeverity,
532 FIL__,
533 __LINE__,
534 status,
535 MSG_SUID_QREPORT,
536 msg, tmp );
537 SH_FREE(tmp);
538 SH_FREE(msg);
539 }
540 }
541 }
542
543 (void) close (readFile);
544 (void) fchmod(writeFile, S_IRUSR | S_IWUSR | S_IXUSR);
545 (void) close (writeFile);
546
547 if (do_truncate (fullpath) == -1)
548 {
549 status = errno;
550 msg = SH_ALLOC(SH_BUFSIZE);
551 tmp = sh_util_safe_name(fullpath);
552
553 (void) sl_snprintf(msg, SH_BUFSIZE,
554 _("Problem quarantining file. File NOT quarantined. errno = %ld"),
555 status);
556 sh_error_handle (ShSuidchkSeverity,
557 FIL__, __LINE__, status,
558 MSG_SUID_QREPORT,
559 msg, tmp );
560 SH_FREE(tmp);
561 SH_FREE(msg);
562 }
563 else
564 {
565 tmp = sh_util_basename(fullpath);
566
567 (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s.info",
568 DEFAULT_QDIR,
569 tmp);
570
571 SH_FREE(tmp);
572 /*
573 * avoid chmod by setting umask
574 */
575 umask_old = umask (0077);
576 filePtr = fopen (filetmp, "w+");
577
578 /*@-usedef@*/
579 if (filePtr)
580 {
581 fprintf(filePtr,
582 _("File Info:\n filename=%s\n size=%lu\n owner=%s(%d)\n group=%s(%d)\n ctime=%s\n atime=%s\n mtime=%s\n"),
583 fullpath,
584 (unsigned long) theFile->size,
585 theFile->c_owner, (int) theFile->owner,
586 theFile->c_group, (int) theFile->group,
587 timestrc, timestra, timestrm);
588 (void) fclose (filePtr);
589 }
590 /*@+usedef@*/
591 umask (umask_old);
592
593 tmp = sh_util_safe_name(fullpath);
594 sh_error_handle (ShSuidchkSeverity,
595 FIL__,__LINE__,
596 0, MSG_SUID_QREPORT,
597 _("Quarantine method applied"),
598 tmp );
599 SH_FREE(tmp);
600 }
601 SH_FREE(filetmp);
602 }
603 }
604 SH_FREE(dir);
605 return;
606}
607
608static void sh_q_changeperm(const char * fullpath)
609{
610 int caperr;
611 int status;
612 char * msg;
613 char * tmp;
614 struct stat fileInfo;
615 struct stat fileInfo_F;
616 int cperm_status = 0;
617 int file_d = -1;
618
619 if (retry_lstat(FIL__, __LINE__, fullpath, &fileInfo) == -1)
620 {
621 status = errno;
622 msg = SH_ALLOC(SH_BUFSIZE);
623 tmp = sh_util_safe_name(fullpath);
624
625 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld"), status);
626 sh_error_handle (ShSuidchkSeverity,
627 FIL__, __LINE__,
628 status,
629 MSG_SUID_QREPORT, msg,
630 tmp );
631 SH_FREE(tmp);
632 SH_FREE(msg);
633 cperm_status = -1;
634 }
635
636 if (cperm_status == 0)
637 {
638 if (0 != (caperr = sl_get_cap_qdel()))
639 {
640 sh_error_handle((-1), FIL__, __LINE__,
641 caperr, MSG_E_SUBGEN,
642 sh_error_message (caperr),
643 _("sl_get_cap_qdel"));
644 cperm_status = -1;
645 }
646 }
647
648 if (cperm_status == 0)
649 {
650 file_d = aud_open (FIL__, __LINE__, SL_YESPRIV,
651 fullpath, O_RDONLY, 0);
652 if (-1 == file_d)
653 {
654 status = errno;
655 msg = SH_ALLOC(SH_BUFSIZE);
656 tmp = sh_util_safe_name(fullpath);
657
658 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld"), status);
659 sh_error_handle (ShSuidchkSeverity,
660 FIL__, __LINE__,
661 status,
662 MSG_SUID_QREPORT, msg,
663 tmp );
664 SH_FREE(tmp);
665 SH_FREE(msg);
666 cperm_status = -1;
667 }
668 }
669
670 if (cperm_status == 0)
671 {
672 if (retry_fstat(FIL__, __LINE__, file_d, &fileInfo_F) == -1)
673 {
674 status = errno;
675 msg = SH_ALLOC(SH_BUFSIZE);
676 tmp = sh_util_safe_name(fullpath);
677
678 (void) sl_snprintf(msg, SH_BUFSIZE,
679 _("I/O error. errno = %ld"), status);
680 sh_error_handle (ShSuidchkSeverity,
681 FIL__, __LINE__,
682 status,
683 MSG_SUID_QREPORT, msg,
684 tmp );
685 SH_FREE(tmp);
686 SH_FREE(msg);
687 cperm_status = -1;
688 }
689 }
690
691 if (cperm_status == 0)
692 {
693 if (fileInfo_F.st_ino != fileInfo.st_ino ||
694 fileInfo_F.st_dev != fileInfo.st_dev ||
695 fileInfo_F.st_mode != fileInfo.st_mode)
696 {
697 status = errno;
698 msg = SH_ALLOC(SH_BUFSIZE);
699 tmp = sh_util_safe_name(fullpath);
700
701 (void) sl_snprintf(msg, SH_BUFSIZE,
702 _("Race detected. errno = %ld"), status);
703 sh_error_handle (ShSuidchkSeverity,
704 FIL__, __LINE__,
705 status,
706 MSG_SUID_QREPORT, msg,
707 tmp );
708 SH_FREE(tmp);
709 SH_FREE(msg);
710 cperm_status = -1;
711 }
712 }
713
714 if ((fileInfo.st_mode & S_ISUID) > 0)
715 fileInfo.st_mode -= S_ISUID;
716 if ((fileInfo.st_mode & S_ISGID) > 0)
717 fileInfo.st_mode -= S_ISGID;
718
719 if (cperm_status == 0)
720 {
721 if (fchmod(file_d, fileInfo.st_mode) == -1)
722 {
723 status = errno;
724 msg = SH_ALLOC(SH_BUFSIZE);
725 tmp = sh_util_safe_name(fullpath);
726
727 (void) sl_snprintf(msg, SH_BUFSIZE,
728 _("Problem quarantining file. File NOT quarantined. errno = %ld"),
729 status);
730 sh_error_handle (ShSuidchkSeverity,
731 FIL__, __LINE__,
732 status,
733 MSG_SUID_QREPORT,
734 msg, tmp );
735 SH_FREE(tmp);
736 SH_FREE(msg);
737 }
738 else
739 {
740 tmp = sh_util_safe_name(fullpath);
741 sh_error_handle (ShSuidchkSeverity,
742 FIL__, __LINE__,
743 0,
744 MSG_SUID_QREPORT,
745 _("Quarantine method applied"),
746 tmp );
747 SH_FREE(tmp);
748 }
749 }
750
751 if (0 != (caperr = sl_drop_cap_qdel()))
752 {
753 sh_error_handle((-1), FIL__, __LINE__,
754 caperr, MSG_E_SUBGEN,
755 sh_error_message (caperr),
756 _("sl_drop_cap_qdel"));
757 }
758
759 if (file_d != -1)
760 {
761 do {
762 status = close (file_d);
763 } while (status == -1 && errno == EINTR);
764
765 if (-1 == status)
766 {
767 status = errno;
768 msg = SH_ALLOC(SH_BUFSIZE);
769 tmp = sh_util_safe_name(fullpath);
770
771 (void) sl_snprintf(msg, SH_BUFSIZE,
772 _("I/O error. errno = %ld"), status);
773 sh_error_handle (ShSuidchkSeverity,
774 FIL__, __LINE__,
775 status,
776 MSG_SUID_QREPORT, msg,
777 tmp );
778 SH_FREE(tmp);
779 SH_FREE(msg);
780 cperm_status = -1;
781 }
782 }
783 return;
784}
785
786static void report_file (const char * tmpcat, file_type * theFile,
787 char * timestrc, char * timestra, char * timestrm)
788{
789 char * msg = SH_ALLOC(SH_BUFSIZE);
790 char * tmp = sh_util_safe_name(tmpcat);
791
792 msg[0] = '\0';
793 /*@-usedef@*/
794 (void) sl_strlcpy (timestrc,
795 sh_unix_gmttime (theFile->ctime),
796 32);
797 (void) sl_strlcpy (timestra,
798 sh_unix_gmttime (theFile->atime),
799 32);
800 (void) sl_strlcpy (timestrm,
801 sh_unix_gmttime (theFile->mtime),
802 32);
803#ifdef SH_USE_XML
804 (void) sl_snprintf(msg, SH_BUFSIZE, _("owner_new=\"%s\" iowner_new=\"%ld\" group_new=\"%s\" igroup_new=\"%ld\" size_new=\"%lu\" ctime_new=\"%s\" atime_new=\"%s\" mtime_new=\"%s\""),
805 theFile->c_owner, theFile->owner,
806 theFile->c_group, theFile->group,
807 (unsigned long) theFile->size,
808 timestrc, timestra, timestrm);
809#else
810 (void) sl_snprintf(msg, SH_BUFSIZE, _("owner_new=<%s>, iowner_new=<%ld>, group_new=<%s>, igroup_new=<%ld>, filesize=<%lu>, ctime=<%s>, atime=<%s>, mtime=<%s>"),
811 theFile->c_owner, theFile->owner,
812 theFile->c_group, theFile->group,
813 (unsigned long) theFile->size,
814 timestrc, timestra, timestrm);
815#endif
816 /*@+usedef@*/
817
818 sh_error_handle (ShSuidchkSeverity, FIL__, __LINE__,
819 0, MSG_SUID_POLICY,
820 _("suid/sgid file not in database"),
821 tmp, msg );
822 SH_FREE(tmp);
823 SH_FREE(msg);
824 return;
825}
826
[1]827static
828int sh_suidchk_check_internal (char * iname)
829{
830 DIR * thisDir = NULL;
831 struct dirent * thisEntry;
832 char * tmpcat;
833 char * tmp;
834 char timestrc[32];
835 char timestra[32];
836 char timestrm[32];
837 struct stat buf;
838 int status;
[115]839 int fflags;
[1]840 char * fs;
841 long sl_status = SL_ENONE;
842 file_type theFile;
[19]843 char fileHash[2*(KEY_LEN + 1)];
[1]844
[131]845 struct sh_dirent * dirlist = NULL;
846 struct sh_dirent * dirlist_orig = NULL;
[22]847
[1]848 SL_ENTER(_("sh_suidchk_check_internal"));
849
850 if (iname == NULL)
851 {
852 TPT((0, FIL__, __LINE__ , _("msg=<directory name is NULL>\n")));
853 SL_RETURN( (-1), _("sh_suidchk_check_internal"));
854 }
855
856 if (sig_urgent > 0) {
857 SL_RETURN( (0), _("sh_suidchk_check_internal"));
858 }
859
860 thisDir = opendir (iname);
861
862 if (thisDir == NULL)
863 {
864 status = errno;
865 tmp = sh_util_safe_name(iname);
866 sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, status,
867 MSG_E_OPENDIR,
868 sh_error_message (status), tmp);
869 SH_FREE(tmp);
870 SL_RETURN( (-1), _("sh_suidchk_check_internal"));
871 }
872
[94]873 /* Loop over directory entries
874 */
[131]875 SH_MUTEX_LOCK(readdir_lock);
876
[1]877 do {
878
879 if (sig_urgent > 0) {
880 SL_RETURN( (0), _("sh_suidchk_check_internal"));
881 }
882
883 thisEntry = readdir (thisDir);
884
885 if (thisEntry != NULL) {
886
887 if (sl_strcmp (thisEntry->d_name, ".") == 0)
888 continue;
889
890 if (sl_strcmp (thisEntry->d_name, "..") == 0)
891 continue;
892
[131]893 dirlist = addto_sh_dirlist (thisEntry, dirlist);
894 }
[1]895
[131]896 } while (thisEntry != NULL);
[94]897
[131]898 SH_MUTEX_UNLOCK(readdir_lock);
[94]899
[131]900 closedir(thisDir);
[1]901
[131]902 dirlist_orig = dirlist;
[1]903
[131]904 do {
905
906 /* If the directory is empty, dirlist = NULL
907 */
908 if (!dirlist)
909 break;
910
911 tmpcat = SH_ALLOC(PATH_MAX);
912 (void) sl_strlcpy(tmpcat, iname, PATH_MAX);
913
914 if ((sl_strlen(tmpcat) != sl_strlen(iname)) || (tmpcat[0] == '\0'))
915 {
916 sl_status = SL_ETRUNC;
917 }
918 else
919 {
920 if (tmpcat[1] != '\0')
921 sl_status = sl_strlcat(tmpcat, "/", PATH_MAX);
922 }
923
924 if (! SL_ISERROR(sl_status))
925 sl_status = sl_strlcat(tmpcat, dirlist->sh_d_name, PATH_MAX);
926
927 if (SL_ISERROR(sl_status))
928 {
929 tmp = sh_util_safe_name(tmpcat);
930 sh_error_handle ((-1), FIL__, __LINE__, (int) sl_status,
931 MSG_E_SUBGPATH,
932 _("path too long"),
933 _("sh_suidchk_check_internal"), tmp );
934 SH_FREE(tmp);
935 dirlist = dirlist->next;
936 continue;
937 }
938
939 ++FileLimNum;
940 ++FileLimTotal;
941
942 /* Rate limit (Fps == Files per second)
943 */
944 if ((ShSuidchkFps > 0 && FileLimNum > ShSuidchkFps && FileLimTotal > 0)&&
945 (ShSuidchkYield == S_FALSE))
946 {
947 FileLimNum = 0;
948 FileLimNow = time(NULL);
949
950 if ( (FileLimNow - FileLimStart) > 0 &&
951 FileLimTotal/(FileLimNow - FileLimStart) > ShSuidchkFps )
952 (void) retry_msleep((int)((FileLimTotal/(FileLimNow-FileLimStart))/
953 ShSuidchkFps) , 0);
954 }
[1]955
[131]956 status = (int) retry_lstat(FIL__, __LINE__, tmpcat, &buf);
[1]957
[131]958 if (status != 0)
959 {
960 status = errno;
961 tmp = sh_util_safe_name(tmpcat);
962 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
963 sh_error_message(status),
964 tmpcat );
965 SH_FREE(tmp);
966 }
967 else
968 {
969 if (/*@-usedef@*/S_ISDIR(buf.st_mode)/*@+usedef@*/ &&
970 (ShSuidchkExclude == NULL ||
971 0 != strcmp(tmpcat, ShSuidchkExclude)))
972 {
973 /* fs is a STATIC string or NULL
974 */
975 fs = filesystem_type (tmpcat, tmpcat, &buf);
976 if (fs != NULL
[30]977#ifndef SH_SUIDTESTDIR
[131]978 &&
979 0 != strncmp (_("afs"), fs, 3) &&
980 0 != strncmp (_("devfs"), fs, 5) &&
981 0 != strncmp (_("iso9660"), fs, 7) &&
982 0 != strncmp (_("lustre"), fs, 6) &&
983 0 != strncmp (_("mmfs"), fs, 4) &&
984 0 != strncmp (_("msdos"), fs, 5) &&
985 0 != strncmp (_("nfs"), fs, 3) &&
986 0 != strncmp (_("proc"), fs, 4) &&
987 0 != strncmp (_("vfat"), fs, 4)
[30]988#endif
[131]989 )
990 {
991 if ((ShSuidchkNosuid == S_TRUE) ||
992 (0 != strncmp (_("nosuid"), fs, 6)))
993 /* fprintf(stderr, "%s: %s\n", fs, tmpcat); */
994 (void) sh_suidchk_check_internal(tmpcat);
995 }
996 }
997 else if (S_ISREG(buf.st_mode) &&
998 (0 !=(S_ISUID & buf.st_mode) ||
[1]999#if defined(HOST_IS_LINUX)
[131]1000 (0 !=(S_ISGID & buf.st_mode) &&
1001 0 !=(S_IXGRP & buf.st_mode))
[1]1002#else
[131]1003 0 !=(S_ISGID & buf.st_mode)
[1]1004#endif
[131]1005 )
1006 )
1007 {
1008
1009 (void) sl_strlcpy (theFile.fullpath, tmpcat, PATH_MAX);
1010 theFile.check_mask = sh_files_maskof(SH_LEVEL_READONLY);
1011 CLEAR_SH_FFLAG_REPORTED(theFile.file_reported);
1012 theFile.attr_string = NULL;
1013
1014 status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO],
1015 thisEntry->d_name,
1016 &theFile, fileHash, 0);
1017
1018 tmp = sh_util_safe_name(tmpcat);
1019
1020 if (status != 0)
1021 {
1022 sh_error_handle (ShSuidchkSeverity, FIL__, __LINE__,
1023 0, MSG_E_SUBGPATH,
1024 _("Could not check suid/sgid file"),
1025 _("sh_suidchk_check_internal"),
1026 tmp);
1027 }
1028 else
1029 {
1030
1031 if ( sh.flag.update == S_TRUE &&
1032 (sh.flag.checkSum == SH_CHECK_INIT ||
1033 sh.flag.checkSum == SH_CHECK_CHECK))
1034 {
1035 /* Updating database. Report new files that
1036 * are not in database already. Then compare
1037 * to database and report changes.
1038 */
1039 if (-1 == sh_hash_have_it (tmpcat))
1040 {
1041 sh_error_handle ((-1), FIL__, __LINE__,
1042 0, MSG_SUID_FOUND, tmp );
1043 }
1044 else
1045 {
1046 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
1047 0, MSG_SUID_FOUND, tmp );
1048 }
1049
1050 if (0 == sh_hash_compdata (SH_LEVEL_READONLY,
1051 &theFile, fileHash,
1052 _("[SuidCheck]"),
1053 ShSuidchkSeverity))
1054 {
1055 sh_hash_pushdata_memory (&theFile, fileHash);
1056 }
1057
1058 sh_hash_addflag(tmpcat, SH_FFLAG_SUIDCHK);
1059
1060 }
1061
1062 else if (sh.flag.checkSum == SH_CHECK_INIT &&
1063 sh.flag.update == S_FALSE )
1064 {
1065 /* Running init. Report on files detected.
1066 */
1067 sh_hash_pushdata (&theFile, fileHash);
1068 sh_error_handle ((-1), FIL__, __LINE__,
1069 0, MSG_SUID_FOUND, tmp );
1070 }
1071
1072 else if (sh.flag.checkSum == SH_CHECK_CHECK )
1073 {
1074 /* Running file check. Report on new files
1075 * detected, and quarantine them.
1076 */
1077 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
1078 0, MSG_SUID_FOUND, tmp );
1079
1080 fflags = sh_hash_getflags(tmpcat);
1081
1082 if ( (-1 == fflags) || (!SH_FFLAG_SUIDCHK_SET(fflags)))
1083 {
1084 if (-1 == fflags)
1085 report_file(tmpcat, &theFile, timestrc, timestra, timestrm);
1086
1087 /* Quarantine file according to configured method
1088 */
1089 if (ShSuidchkQEnable == S_TRUE)
1090 {
1091 switch (ShSuidchkQMethod)
1092 {
1093 case SH_Q_DELETE:
1094 sh_q_delete(theFile.fullpath);
1095 break;
1096 case SH_Q_CHANGEPERM:
1097 sh_q_changeperm(theFile.fullpath);
1098 break;
1099 case SH_Q_MOVE:
1100 sh_q_move(theFile.fullpath, &theFile, timestrc, timestra, timestrm);
1101 break;
1102 default:
1103 sh_error_handle (ShSuidchkSeverity, FIL__,
1104 __LINE__, 0, MSG_SUID_QREPORT,
1105 _("Bad quarantine method"), tmp);
1106 break;
1107 }
1108 }
1109 else
1110 {
1111 /* 1.8.1 push file to in-memory database
1112 */
1113 (void) sh_hash_compdata (SH_LEVEL_READONLY,
1114 &theFile, fileHash,
1115 _("[SuidCheck]"),
1116 ShSuidchkSeverity);
1117
1118 sh_hash_addflag(tmpcat, SH_FFLAG_SUIDCHK);
1119
1120 }
1121 }
1122 else
1123 {
1124 /* File exists. Check for modifications.
1125 */
1126 (void) sh_hash_compdata (SH_LEVEL_READONLY,
[1]1127 &theFile, fileHash,
[131]1128 _("[SuidCheck]"),
1129 ShSuidchkSeverity);
1130
1131 sh_hash_addflag(tmpcat, SH_FFLAG_SUIDCHK);
1132
1133 }
1134 }
1135 }
1136 SH_FREE(tmp);
1137 if (theFile.attr_string)
1138 SH_FREE(theFile.attr_string);
1139 }
1140 }
1141 SH_FREE(tmpcat);
[115]1142
[131]1143
[1]1144#ifdef HAVE_SCHED_YIELD
1145 if (ShSuidchkYield == S_TRUE)
1146 {
1147 if (sched_yield() == -1)
1148 {
1149 status = errno;
1150 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
[131]1151 _("Failed to release time slice"),
[1]1152 _("sh_suidchk_check_internal") );
1153 }
1154 }
1155#endif
[131]1156
1157 dirlist = dirlist->next;
[68]1158
[131]1159 } while (dirlist != NULL);
[1]1160
[131]1161
1162 kill_sh_dirlist (dirlist_orig);
1163
[1]1164 SL_RETURN( (0), _("sh_suidchk_check_internal"));
1165}
1166
1167/*************
1168 *
1169 * module init
1170 *
1171 *************/
1172int sh_suidchk_init ()
1173{
1174 if (ShSuidchkActive == S_FALSE)
1175 return (-1);
1176
1177 return (0);
1178}
1179
1180
1181/*************
1182 *
1183 * module cleanup
1184 *
1185 *************/
1186int sh_suidchk_end ()
1187{
1188 return (0);
1189}
1190
1191
1192/*************
1193 *
1194 * module timer
1195 *
1196 *************/
1197int sh_suidchk_timer (time_t tcurrent)
1198{
1199 if (sh.flag.checkSum == SH_CHECK_INIT)
1200 return -1;
1201
1202 /* One-shot (not daemon and not loop forever)
1203 */
1204 if (sh.flag.isdaemon != S_TRUE && sh.flag.loop == S_FALSE)
1205 return -1;
1206
1207 if (ShSuidchkSched != NULL)
1208 {
1209 return test_sched(ShSuidchkSched);
1210 }
1211 if ((time_t) (tcurrent - lastcheck) >= ShSuidchkInterval)
1212 {
1213 lastcheck = tcurrent;
1214 return (-1);
1215 }
1216 return 0;
1217}
1218
1219/*************
1220 *
1221 * module check
1222 *
1223 *************/
1224
1225int sh_suidchk_check ()
1226{
1227 int status;
1228
1229 SL_ENTER(_("sh_suidchk_check"));
1230
1231 sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
1232 _("Checking for SUID programs"),
1233 _("suidchk_check") );
1234
1235 FileLimNow = time(NULL);
1236 FileLimStart = FileLimNow;
1237 FileLimNum = 0;
1238 FileLimTotal = 0;
1239
[22]1240#ifdef SH_SUIDTESTDIR
1241 status = sh_suidchk_check_internal (SH_SUIDTESTDIR);
1242#else
[1]1243 status = sh_suidchk_check_internal ("/");
[22]1244#endif
[1]1245
1246 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_SUID_SUMMARY,
1247 FileLimTotal,
1248 (long) (time(NULL) - FileLimStart) );
1249
1250 SL_RETURN(status, _("sh_suidchk_check"));
1251}
1252
1253/*************
1254 *
1255 * module setup
1256 *
1257 *************/
1258
[68]1259int sh_suidchk_set_severity (const char * c)
[1]1260{
1261 int retval;
1262 char tmp[32];
1263
1264 SL_ENTER(_("sh_suidchk_set_severity"));
1265 tmp[0] = '='; tmp[1] = '\0';
1266 (void) sl_strlcat (tmp, c, 32);
1267 retval = sh_error_set_level (tmp, &ShSuidchkSeverity);
1268 SL_RETURN(retval, _("sh_suidchk_set_severity"));
1269}
1270
[68]1271int sh_suidchk_set_exclude (const char * c)
[1]1272{
1273 SL_ENTER(_("sh_suidchk_set_exclude"));
[68]1274
[1]1275 if (c == NULL || c[0] == '\0')
1276 {
1277 SL_RETURN(-1, _("sh_suidchk_set_exclude"));
1278 }
1279
1280 if (0 == sl_strncmp(c, _("NULL"), 4))
1281 {
1282 if (ShSuidchkExclude != NULL)
1283 SH_FREE(ShSuidchkExclude);
1284 ShSuidchkExclude = NULL;
1285 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1286 }
1287
1288 if (ShSuidchkExclude != NULL)
1289 SH_FREE(ShSuidchkExclude);
1290
[68]1291 ShSuidchkExclude = sh_util_strdup (c);
1292 ExcludeLen = sl_strlen (ShSuidchkExclude);
1293 if (ShSuidchkExclude[ExcludeLen-1] == '/')
[1]1294 {
[68]1295 ShSuidchkExclude[ExcludeLen-1] = '\0';
[55]1296 ExcludeLen--;
[1]1297 }
1298 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1299}
1300
[68]1301int sh_suidchk_set_timer (const char * c)
[1]1302{
1303 long val;
1304
1305 SL_ENTER(_("sh_suidchk_set_timer"));
1306
1307 val = strtol (c, (char **)NULL, 10);
1308 if (val <= 0)
1309 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1310 _("suidchk timer"), c);
1311
1312 val = (val <= 0 ? 7200 : val);
1313
1314 ShSuidchkInterval = (time_t) val;
1315 SL_RETURN( 0, _("sh_suidchk_set_timer"));
1316}
1317
1318
1319int sh_suidchk_free_schedule ()
1320{
1321 sh_schedule_t * current = ShSuidchkSched;
1322 sh_schedule_t * next = NULL;
1323
1324 while (current != NULL)
1325 {
1326 next = current->next;
1327 SH_FREE(current);
1328 current = next;
1329 }
1330 ShSuidchkSched = NULL;
1331 return 0;
1332}
1333
[68]1334int sh_suidchk_set_schedule (const char * str)
[1]1335{
1336 int status;
1337 sh_schedule_t * newSched = NULL;
1338
1339 SL_ENTER(_("sh_suidchk_set_schedule"));
1340
1341 /*
1342 if (ShSuidchkSched != NULL)
1343 {
1344 SH_FREE(ShSuidchkSched);
1345 ShSuidchkSched = NULL;
1346 }
1347 */
1348
1349 if (0 == sl_strncmp(str, _("NULL"), 4))
1350 {
1351 (void) sh_suidchk_free_schedule ();
1352 return 0;
1353 }
1354
1355 newSched = SH_ALLOC(sizeof(sh_schedule_t));
1356 status = create_sched(str, newSched);
1357 if (status != 0)
1358 {
1359 SH_FREE(newSched);
1360 newSched = NULL;
1361 }
1362 else
1363 {
1364 newSched->next = ShSuidchkSched;
1365 ShSuidchkSched = newSched;
1366 }
1367 SL_RETURN( status, _("sh_suidchk_set_schedule"));
1368}
1369
1370
1371
[68]1372int sh_suidchk_set_fps (const char * c)
[1]1373{
1374 long val;
1375
1376 SL_ENTER(_("sh_suidchk_set_fps"));
1377
1378 val = strtol (c, (char **)NULL, 10);
1379 if (val < 0)
1380 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1381 _("suidchk fps"), c);
1382
1383 val = (val < 0 ? 0 : val);
1384
1385 ShSuidchkFps = val;
1386 SL_RETURN( 0, _("sh_suidchk_set_fps"));
1387}
1388
[68]1389int sh_suidchk_set_yield (const char * c)
[1]1390{
1391 int i;
1392 SL_ENTER(_("sh_suidchk_set_yield"));
1393#ifdef HAVE_SCHED_YIELD
1394 i = sh_util_flagval(c, &ShSuidchkYield);
1395#else
1396 (void) c; /* cast to void to avoid compiler warning */
1397 i = -1;
1398#endif
1399 SL_RETURN(i, _("sh_suidchk_set_yield"));
1400}
1401
[68]1402int sh_suidchk_set_activate (const char * c)
[1]1403{
1404 int i;
1405 SL_ENTER(_("sh_suidchk_set_activate"));
1406 i = sh_util_flagval(c, &ShSuidchkActive);
1407 SL_RETURN(i, _("sh_suidchk_set_activate"));
1408}
1409
[119]1410int sh_suidchk_set_nosuid (const char * c)
1411{
1412 int i;
1413 SL_ENTER(_("sh_suidchk_set_nosuid"));
1414 i = sh_util_flagval(c, &ShSuidchkNosuid);
1415 SL_RETURN(i, _("sh_suidchk_set_nosuid"));
1416}
1417
[68]1418int sh_suidchk_set_quarantine (const char * c)
[1]1419{
1420 int i;
1421 SL_ENTER(_("sh_suidchk_set_quarantine"));
1422 i = sh_util_flagval(c, &ShSuidchkQEnable);
1423 SL_RETURN(i, _("sh_suidchk_set_quarantine"));
1424}
1425
[68]1426int sh_suidchk_set_qdelete (const char * c)
[1]1427{
1428 int i;
1429 SL_ENTER(_("sh_suidchk_set_qdelete"));
1430 i = sh_util_flagval(c, &ShSuidchkQDelete);
1431 SL_RETURN(i, _("sh_suidchk_set_qdelete"));
1432}
1433
[68]1434int sh_suidchk_set_qmethod (const char * c)
[1]1435{
1436 long val;
1437 int ret = 0;
[22]1438 struct stat buf;
[1]1439
1440 SL_ENTER(_("sh_suidchk_set_qmethod"));
1441
1442 val = strtol (c, (char **)NULL, 10);
1443 if (val < 0)
1444 {
1445 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1446 _("suidchk qmethod"), c);
1447 ret = -1;
1448 }
1449 else
1450 {
1451 switch (val)
1452 {
1453 case SH_Q_DELETE:
1454 ShSuidchkQMethod = SH_Q_DELETE;
1455 break;
1456 case SH_Q_CHANGEPERM:
1457 ShSuidchkQMethod = SH_Q_CHANGEPERM;
1458 break;
1459 case SH_Q_MOVE:
[22]1460 if (retry_stat (FIL__, __LINE__, DEFAULT_QDIR, &buf) != 0)
[1]1461 {
1462 if (mkdir (DEFAULT_QDIR, 0750) == -1)
1463 {
1464 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
1465 MSG_SUID_ERROR,
1466 _("Unable to create quarantine directory"));
1467 }
1468 }
1469 ShSuidchkQMethod = SH_Q_MOVE;
1470 break;
1471 default:
1472 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1473 _("suidchk qmethod"), c);
1474 ShSuidchkQMethod = -1;
1475 ret = -1;
1476 break;
1477 }
1478 }
1479
1480 SL_RETURN( ret, _("sh_suidchk_set_qmethod"));
1481}
1482
1483#if defined(FSTYPE_STATFS) || defined(FSTYPE_AIX_STATFS)
1484/* dirname.c -- return all but the last element in a path
1485 Copyright (C) 1990 Free Software Foundation, Inc.
1486
1487 This program is free software; you can redistribute it and/or modify
1488 it under the terms of the GNU General Public License as published by
1489 the Free Software Foundation; either version 2, or (at your option)
1490 any later version.
1491
1492 This program is distributed in the hope that it will be useful,
1493 but WITHOUT ANY WARRANTY; without even the implied warranty of
1494 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1495 GNU General Public License for more details.
1496
1497 You should have received a copy of the GNU General Public License
1498 along with this program; if not, write to the Free Software Foundation,
1499 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
1500
1501/* Return the leading directories part of PATH,
1502 allocated with malloc. If out of memory, return 0.
1503 Assumes that trailing slashes have already been
1504 removed. */
1505
1506char * sh_dirname (const char * path)
1507{
1508 char *newpath;
1509 char *slash;
1510 int length; /* Length of result, not including NUL. */
1511
1512 slash = strrchr (path, '/');
1513 if (slash == NULL)
1514 {
1515 /* File is in the current directory. */
1516 path = ".";
1517 length = 1;
1518 }
1519 else
1520 {
1521 /* Remove any trailing slashes from the result. */
1522 while (slash > path && *slash == '/')
1523 --slash;
1524
1525 length = slash - path + 1;
1526 }
1527 newpath = (char *) SH_ALLOC (length + 1);
1528 if (newpath == NULL)
1529 return NULL;
1530 strncpy (newpath, path, length);
1531 newpath[length] = '\0';
1532 return newpath;
1533}
1534/* #ifdef FSTYPE_STATFS */
1535#endif
1536
1537/* fstype.c -- determine type of filesystems that files are on
1538 Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
1539
1540 This program is free software; you can redistribute it and/or modify
1541 it under the terms of the GNU General Public License as published by
1542 the Free Software Foundation; either version 2, or (at your option)
1543 any later version.
1544
1545 This program is distributed in the hope that it will be useful,
1546 but WITHOUT ANY WARRANTY; without even the implied warranty of
1547 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1548 GNU General Public License for more details.
1549
1550 You should have received a copy of the GNU General Public License
1551 along with this program; if not, write to the Free Software
1552 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
1553
1554/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
1555
1556/* Modified by R. Wichmann:
1557 - replaced error() by sh_error_handle()
1558 - replaced xstrdup() by sl_strdup()
1559 - replaced strstr() by sl_strstr()
1560 - some additions to recognize nosuid fs
1561*/
1562
1563/* modetype.h -- file type bits definitions for POSIX systems
1564 Requires sys/types.h sys/stat.h.
1565 Copyright (C) 1990 Free Software Foundation, Inc.
1566
1567 This program is free software; you can redistribute it and/or modify
1568 it under the terms of the GNU General Public License as published by
1569 the Free Software Foundation; either version 2, or (at your option)
1570 any later version.
1571
1572 This program is distributed in the hope that it will be useful,
1573 but WITHOUT ANY WARRANTY; without even the implied warranty of
1574 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1575 GNU General Public License for more details.
1576
1577 You should have received a copy of the GNU General Public License
1578 along with this program; if not, write to the Free Software
1579 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
1580
1581/* POSIX.1 doesn't mention the S_IFMT bits; instead, it uses S_IStype
1582 test macros. To make storing file types more convenient, define
1583 them; the values don't need to correspond to what the kernel uses,
1584 because of the way we use them. */
1585#ifndef S_IFMT /* Doesn't have traditional Unix macros. */
1586#define S_IFBLK 1
1587#define S_IFCHR 2
1588#define S_IFDIR 4
1589#define S_IFREG 8
1590#ifdef S_ISLNK
1591#define S_IFLNK 16
1592#endif
1593#ifdef S_ISFIFO
1594#define S_IFIFO 32
1595#endif
1596#ifdef S_ISSOCK
1597#define S_IFSOCK 64
1598#endif
1599#endif /* !S_IFMT */
1600
1601#ifdef STAT_MACROS_BROKEN
1602#undef S_ISBLK
1603#undef S_ISCHR
1604#undef S_ISDIR
1605#undef S_ISREG
1606#undef S_ISFIFO
1607#undef S_ISLNK
1608#undef S_ISSOCK
1609#undef S_ISMPB
1610#undef S_ISMPC
1611#undef S_ISNWK
1612#endif
1613
1614/* Do the reverse: define the POSIX.1 macros for traditional Unix systems
1615 that don't have them. */
1616#if !defined(S_ISBLK) && defined(S_IFBLK)
1617#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
1618#endif
1619#if !defined(S_ISCHR) && defined(S_IFCHR)
1620#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
1621#endif
1622#if !defined(S_ISDIR) && defined(S_IFDIR)
1623#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1624#endif
1625#if !defined(S_ISREG) && defined(S_IFREG)
1626#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1627#endif
1628#if !defined(S_ISFIFO) && defined(S_IFIFO)
1629#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
1630#endif
1631#if !defined(S_ISLNK) && defined(S_IFLNK)
1632#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1633#endif
1634#if !defined(S_ISSOCK) && defined(S_IFSOCK)
1635#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
1636#endif
1637#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
1638#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
1639#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
1640#endif
1641#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
1642#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
1643#endif
1644
1645
1646static char *filesystem_type_uncached (char *path, char *relpath,
1647 struct stat *statp);
1648
1649#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
1650static int xatoi (char *cp);
1651#endif
1652
1653#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
1654#include <mntent.h>
1655#if !defined(MOUNTED)
1656# if defined(MNT_MNTTAB) /* HP-UX. */
1657# define MOUNTED MNT_MNTTAB
1658# endif
1659# if defined(MNTTABNAME) /* Dynix. */
1660# define MOUNTED MNTTABNAME
1661# endif
1662#endif
1663#endif
1664
1665#ifdef FSTYPE_GETMNT /* Ultrix. */
1666#include <sys/param.h>
1667#include <sys/mount.h>
1668#include <sys/fs_types.h>
1669#endif
1670
1671#ifdef FSTYPE_USG_STATFS /* SVR3. */
1672#include <sys/statfs.h>
1673#include <sys/fstyp.h>
1674#endif
1675
1676#ifdef FSTYPE_STATVFS /* SVR4. */
1677#include <sys/statvfs.h>
1678#include <sys/fstyp.h>
1679#endif
1680
1681#ifdef FSTYPE_STATFS /* 4.4BSD. */
1682#include <sys/param.h> /* NetBSD needs this. */
1683#include <sys/mount.h>
1684
1685#ifndef MFSNAMELEN /* NetBSD defines this. */
1686static char *
1687fstype_to_string (t)
1688 short t;
1689{
1690#ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
1691 static char *mn[] = INITMOUNTNAMES;
1692 if (t >= 0 && t <= MOUNT_MAXTYPE)
1693 return mn[t];
1694 else
1695 return "?";
1696#else /* !INITMOUNTNAMES */
1697 switch (t)
1698 {
1699 case MOUNT_UFS:
1700 return _("ufs");
1701 case MOUNT_NFS:
1702 return _("nfs");
1703#ifdef MOUNT_PC
1704 case MOUNT_PC:
1705 return _("pc");
1706#endif
1707#ifdef MOUNT_MFS
1708 case MOUNT_MFS:
1709 return _("mfs");
1710#endif
1711#ifdef MOUNT_LO
1712 case MOUNT_LO:
1713 return _("lofs");
1714#endif
1715#ifdef MOUNT_TFS
1716 case MOUNT_TFS:
1717 return _("tfs");
1718#endif
1719#ifdef MOUNT_TMP
1720 case MOUNT_TMP:
1721 return _("tmp");
1722#endif
1723#ifdef MOUNT_MSDOS
1724 case MOUNT_MSDOS:
1725 return _("msdos");
1726#endif
1727#ifdef MOUNT_ISO9660
1728 case MOUNT_ISO9660:
1729 return _("iso9660fs");
1730#endif
1731 default:
1732 return "?";
1733 }
1734#endif /* !INITMOUNTNAMES */
1735}
1736#endif /* !MFSNAMELEN */
1737#endif /* FSTYPE_STATFS */
1738
1739#ifdef FSTYPE_AIX_STATFS /* AIX. */
1740#include <sys/vmount.h>
1741#include <sys/statfs.h>
1742
1743#define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
1744#define f_type f_vfstype
1745
1746static char *
1747fstype_to_string (t)
1748 short t;
1749{
1750 switch (t)
1751 {
1752 case MNT_AIX:
1753 return _("aix"); /* AIX 4.3: NFS filesystems are actually MNT_AIX. */
1754#ifdef MNT_NAMEFS
1755 case MNT_NAMEFS:
1756 return _("namefs");
1757#endif
1758 case MNT_NFS:
1759 return _("nfs");
1760 case MNT_JFS:
1761 return _("jfs");
1762 case MNT_CDROM:
1763 return _("cdrom");
1764#ifdef MNT_PROCFS
1765 case MNT_PROCFS:
1766 return _("procfs");
1767#endif
1768#ifdef MNT_SFS
1769 case MNT_SFS:
1770 return _("sfs");
1771#endif
1772#ifdef MNT_CACHEFS
1773 case MNT_CACHEFS:
1774 return _("cachefs");
1775#endif
1776#ifdef MNT_NFS3
1777 case MNT_NFS3:
1778 return _("nfs3");
1779#endif
1780#ifdef MNT_AUTOFS
1781 case MNT_AUTOFS:
1782 return _("autofs");
1783#endif
1784#ifdef MNT_VXFS
1785 case MNT_VXFS:
1786 return _("vxfs");
1787#endif
1788#ifdef MNT_VXODM
1789 case MNT_VXODM:
1790 return _("veritasfs");
1791#endif
1792#ifdef MNT_UDF
1793 case MNT_UDF:
1794 return _("udfs");
1795#endif
1796#ifdef MNT_NFS4
1797 case MNT_NFS4:
1798 return _("nfs4");
1799#endif
1800#ifdef MNT_RFS4
1801 case MNT_RFS4:
1802 return _("nfs4");
1803#endif
1804#ifdef MNT_CIFS
1805 case MNT_CIFS:
1806 return _("cifs");
1807#endif
1808 default:
1809 return "?";
1810 }
1811}
1812#endif /* FSTYPE_AIX_STATFS */
1813
1814#ifdef AFS
1815#include <netinet/in.h>
1816#include <afs/venus.h>
1817#if __STDC__
1818/* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
1819#undef _VICEIOCTL
1820#define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
1821#endif
1822#ifndef _IOW
1823/* AFS on Solaris 2.3 doesn't get this definition. */
1824#include <sys/ioccom.h>
1825#endif
1826
1827static int
1828in_afs (path)
1829 char *path;
1830{
1831 static char space[2048];
1832 struct ViceIoctl vi;
1833
1834 vi.in_size = 0;
1835 vi.out_size = sizeof (space);
1836 vi.out = space;
1837
1838 if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
1839 && (errno == EINVAL || errno == ENOENT))
1840 return 0;
1841 return 1;
1842}
1843#endif /* AFS */
1844
1845/* Nonzero if the current filesystem's type is known. */
1846static int fstype_known = 0;
1847
1848/* Return a static string naming the type of filesystem that the file PATH,
1849 described by STATP, is on.
1850 RELPATH is the file name relative to the current directory.
1851 Return "unknown" if its filesystem type is unknown. */
1852
1853static char *
1854filesystem_type (char * path, char * relpath, struct stat * statp)
1855{
1856 static char *current_fstype = NULL;
1857 static dev_t current_dev;
1858
1859 if (current_fstype != NULL)
1860 {
1861 if ((0 != fstype_known) && statp->st_dev == current_dev)
1862 return current_fstype; /* Cached value. */
1863 SH_FREE (current_fstype);
1864 }
1865 current_dev = statp->st_dev;
1866 current_fstype = filesystem_type_uncached (path, relpath, statp);
1867 return current_fstype;
1868}
1869
1870/* Return a newly allocated string naming the type of filesystem that the
1871 file PATH, described by STATP, is on.
1872 RELPATH is the file name relative to the current directory.
1873 Return "unknown" if its filesystem type is unknown. */
1874
1875static char *
1876filesystem_type_uncached (path, relpath, statp)
1877 char *path;
1878 char *relpath;
1879 struct stat *statp;
1880{
1881 char * type = NULL;
1882#ifdef MFSNAMELEN /* NetBSD. */
1883 static char my_tmp_type[64];
1884#endif
1885
1886#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
1887 char *table = MOUNTED;
1888 FILE *mfp;
1889 struct mntent *mnt;
1890
1891 if (path == NULL || relpath == NULL)
1892 return NULL;
1893
1894 mfp = setmntent (table, "r");
1895 if (mfp == NULL)
1896 {
1897 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1898 _("setmntent() failed"),
1899 _("filesystem_type_uncached") );
1900 return NULL;
1901 }
1902
1903 /* Find the entry with the same device number as STATP, and return
1904 that entry's fstype. */
1905 while (type == NULL && (mnt = getmntent (mfp)) != NULL)
1906 {
1907 char *devopt;
1908 dev_t dev;
1909 struct stat disk_stats;
1910
1911#ifdef MNTTYPE_IGNORE
1912 if (0 == strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
1913 continue;
1914#endif
1915
1916 /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
1917 in the options string. For older systems, we need to stat the
1918 directory that the filesystem is mounted on to get it.
1919
1920 Unfortunately, the HPUX 9.x mnttab entries created by automountq
1921 contain a dev= option but the option value does not match the
1922 st_dev value of the file (maybe the lower 16 bits match?). */
1923
1924#if !defined(hpux) && !defined(__hpux__)
1925 devopt = sl_strstr (mnt->mnt_opts, "dev=");
1926 if (devopt)
1927 {
1928 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
1929 dev = (dev_t) xatoi (devopt + 6);
1930 else
1931 dev = (dev_t) xatoi (devopt + 4);
1932 }
1933 else
1934#endif /* not hpux */
1935 {
1936 if (stat (mnt->mnt_dir, &disk_stats) == -1)
1937 {
1938 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1939 _("stat() failed"),
1940 _("filesystem_type_uncached") );
1941 return NULL;
1942 }
1943 dev = disk_stats.st_dev;
1944 }
1945
1946 if (dev == statp->st_dev)
1947 {
1948 /* check for the "nosuid" option
1949 */
[61]1950#ifdef HAVE_HASMNTOPT
[119]1951 if (NULL == hasmntopt(mnt, "nosuid") || (ShSuidchkNosuid == S_TRUE))
[1]1952 type = mnt->mnt_type;
1953 else
[61]1954 type = _("nosuid"); /* hasmntopt (nosuid) */
1955#else
1956 type = mnt->mnt_type;
1957#endif
[1]1958 }
1959 }
1960
1961 if (endmntent (mfp) == 0)
1962 {
1963 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1964 _("endmntent() failed"),
1965 _("filesystem_type_uncached") );
1966 }
1967#endif
1968
1969#ifdef FSTYPE_GETMNT /* Ultrix. */
1970 int offset = 0;
1971 struct fs_data fsd;
1972
1973 if (path == NULL || relpath == NULL)
1974 return NULL;
1975
1976 while (type == NULL
1977 && getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 0) > 0)
1978 {
1979 if (fsd.fd_req.dev == statp->st_dev)
1980 type = gt_names[fsd.fd_req.fstype];
1981 }
1982#endif
1983
1984#ifdef FSTYPE_USG_STATFS /* SVR3. */
1985 struct statfs fss;
1986 char typebuf[FSTYPSZ];
1987
1988 if (path == NULL || relpath == NULL)
1989 return NULL;
1990
1991 if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
1992 {
1993 /* Don't die if a file was just removed. */
1994 if (errno != ENOENT)
1995 {
1996 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1997 _("statfs() failed"),
1998 _("filesystem_type_uncached") );
1999 return NULL;
2000 }
2001 }
2002 else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
2003 type = typebuf;
2004#endif
2005
2006#ifdef FSTYPE_STATVFS /* SVR4. */
2007 struct statvfs fss;
2008
2009 if (path == NULL || relpath == NULL)
2010 return NULL;
2011
2012 if (statvfs (relpath, &fss) == -1)
2013 {
2014 /* Don't die if a file was just removed. */
2015 if (errno != ENOENT)
2016 {
2017 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
2018 _("statvfs() failed"),
2019 _("filesystem_type_uncached") );
2020 return NULL;
2021 }
2022 }
2023 else
2024 {
2025 type = fss.f_basetype;
2026
2027 /* patch by Konstantin Khrooschev <nathoo@co.ru>
2028 */
[119]2029 if( (fss.f_flag & ST_NOSUID) && (ShSuidchkNosuid == S_FALSE))
[1]2030 type = _("nosuid");
2031 }
2032 (void) statp; /* fix compiler warning */
2033#endif
2034
2035#ifdef FSTYPE_STATFS /* 4.4BSD. */
2036 struct statfs fss;
2037 char *p;
2038#if defined(MNT_VISFLAGMASK) && defined(HAVE_STRUCT_STATFS_F_FLAGS)
2039 int flags;
2040#endif
2041 /* char * sh_dirname(const char *path); */
2042
2043 if (path == NULL || relpath == NULL)
2044 return NULL;
2045
2046 if (S_ISLNK (statp->st_mode))
2047 p = sh_dirname (relpath);
2048 else
2049 p = relpath;
2050
2051 if (statfs (p, &fss) == -1)
2052 {
2053 /* Don't die if symlink to nonexisting file, or a file that was
2054 just removed. */
2055 if (errno != ENOENT)
2056 {
2057 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
2058 _("statfs() failed"),
2059 _("filesystem_type_uncached") );
2060 return NULL;
2061 }
2062 }
2063 else
2064 {
2065
2066#ifdef MFSNAMELEN /* NetBSD. */
2067 /* MEMORY LEAK !!!
2068 * type = sh_util_strdup (fss.f_fstypename);
2069 */
2070 sl_strlcpy (my_tmp_type, fss.f_fstypename, 64);
2071 type = my_tmp_type;
2072#else
2073 type = fstype_to_string (fss.f_type);
2074#endif
2075
2076#ifdef HAVE_STRUCT_STATFS_F_FLAGS
2077#ifdef MNT_VISFLAGMASK
2078 flags = fss.f_flags & MNT_VISFLAGMASK;
[119]2079 if ((flags & MNT_NOSUID) && (ShSuidchkNosuid == S_FALSE))
[1]2080#else
[119]2081 if ((fss.f_flags & MNT_NOSUID) && (ShSuidchkNosuid == S_FALSE))
[1]2082#endif
2083 type = _("nosuid");
2084#endif
2085 }
2086 if (p != relpath)
2087 SH_FREE (p);
2088#endif
2089
2090#ifdef AFS
2091 if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
2092 type = "afs";
2093#endif
2094
2095 /* An unknown value can be caused by an ENOENT error condition.
2096 Don't cache those values. */
2097 fstype_known = (int)(type != NULL);
2098
2099 return sh_util_strdup (type ? type : "unknown");
2100}
2101
2102#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
2103/* Return the value of the hexadecimal number represented by CP.
2104 No prefix (like '0x') or suffix (like 'h') is expected to be
2105 part of CP. */
2106
2107static int
2108xatoi (cp)
2109 char *cp;
2110{
2111 int val;
2112
2113 val = 0;
2114 while (*cp != '\0')
2115 {
2116 /*@+charint@*/
2117 if (*cp >= 'a' && *cp <= 'f')
2118 val = val * 16 + *cp - 'a' + 10;
2119 else if (*cp >= 'A' && *cp <= 'F')
2120 val = val * 16 + *cp - 'A' + 10;
2121 else if (*cp >= '0' && *cp <= '9')
2122 val = val * 16 + *cp - '0';
2123 else
2124 break;
2125 /*@-charint@*/
2126 cp++;
2127 }
2128 return val;
2129}
2130#endif
2131
2132
2133
2134#endif
2135
2136
2137/* #ifdef SH_USE_UTMP */
2138#endif
2139
2140
2141
Note: See TracBrowser for help on using the repository browser.