source: trunk/src/sh_suidchk.c@ 27

Last change on this file since 27 was 22, checked in by rainer, 19 years ago

Minor code revisions.

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