source: trunk/src/sh_suidchk.c@ 92

Last change on this file since 92 was 68, checked in by rainer, 18 years ago

Update trunk to samhain 2.3

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