source: trunk/src/sh_suidchk.c@ 110

Last change on this file since 110 was 94, checked in by rainer, 18 years ago

Refactoring of sh_suidchk.c

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