source: trunk/src/sh_suidchk.c@ 29

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

Fixes for test suite, OpenBSD portability, self-resolving, and suidchk patch by Neil

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 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 (_("afs"), fs, 3) &&
528 0 != strncmp (_("devfs"), fs, 5) &&
529 0 != strncmp (_("iso9660"), fs, 7) &&
530 0 != strncmp (_("lustre"), fs, 6) &&
531 0 != strncmp (_("mmfs"), fs, 4) &&
532 0 != strncmp (_("msdos"), fs, 5) &&
533 0 != strncmp (_("nfs"), fs, 3) &&
534 0 != strncmp (_("nosuid"), fs, 6) &&
535 0 != strncmp (_("proc"), fs, 4) &&
536 0 != strncmp (_("vfat"), fs, 4)
537 )
538 {
539 /* fprintf(stderr, "%s: %s\n", fs, tmpcat); */
540 (void) sh_suidchk_check_internal(tmpcat);
541 }
542 }
543 else if (S_ISREG(buf.st_mode) &&
544 (0 !=(S_ISUID & buf.st_mode) ||
545#if defined(HOST_IS_LINUX)
546 (0 !=(S_ISGID & buf.st_mode) &&
547 0 !=(S_IXGRP & buf.st_mode))
548#else
549 0 !=(S_ISGID & buf.st_mode)
550#endif
551 )
552 )
553 {
554
555 (void) sl_strlcpy (theFile.fullpath, tmpcat, PATH_MAX);
556 theFile.check_mask = sh_files_maskof(SH_LEVEL_READONLY);
557 theFile.reported = S_FALSE;
558 status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO],
559 thisEntry->d_name,
560 &theFile, fileHash, 0);
561
562 tmp = sh_util_safe_name(tmpcat);
563
564 if (status != 0)
565 {
566 sh_error_handle (ShSuidchkSeverity, FIL__, __LINE__,
567 0, MSG_E_SUBGPATH,
568 _("Could not check suid/sgid file"),
569 _("sh_suidchk_check_internal"),
570 tmp);
571 }
572 else
573 {
574 if (sh.flag.update == S_TRUE &&
575 (sh.flag.checkSum == SH_CHECK_INIT ||
576 sh.flag.checkSum == SH_CHECK_CHECK))
577 {
578 if (-1 == sh_hash_have_it (tmpcat))
579 {
580 sh_error_handle ((-1), FIL__, __LINE__,
581 0, MSG_SUID_FOUND,
582 tmp );
583 }
584 else
585 {
586 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
587 0, MSG_SUID_FOUND,
588 tmp );
589 }
590 if (0 == sh_hash_compdata (SH_LEVEL_READONLY,
591 &theFile, fileHash,
592 _("[SuidCheck]"),
593 ShSuidchkSeverity))
594 {
595 sh_hash_pushdata_memory (&theFile, fileHash);
596 }
597 }
598 else if (sh.flag.checkSum == SH_CHECK_INIT &&
599 sh.flag.update == S_FALSE )
600 {
601 sh_hash_pushdata (&theFile, fileHash);
602 sh_error_handle ((-1), FIL__, __LINE__,
603 0, MSG_SUID_FOUND,
604 tmp );
605 }
606 else if (sh.flag.checkSum == SH_CHECK_CHECK )
607 {
608 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
609 0, MSG_SUID_FOUND,
610 tmp );
611 if (-1 == sh_hash_have_it (tmpcat))
612 {
613 msg = SH_ALLOC(SH_BUFSIZE);
614 msg[0] = '\0';
615 /*@-usedef@*/
616 (void) sl_strlcpy (timestrc,
617 sh_unix_gmttime (theFile.ctime),
618 32);
619 (void) sl_strlcpy (timestra,
620 sh_unix_gmttime (theFile.atime),
621 32);
622 (void) sl_strlcpy (timestrm,
623 sh_unix_gmttime (theFile.mtime),
624 32);
625#ifdef SH_USE_XML
626 (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\""),
627 theFile.c_owner, theFile.owner,
628 theFile.c_group, theFile.group,
629 (unsigned long) theFile.size,
630 timestrc, timestra, timestrm);
631#else
632 (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>"),
633 theFile.c_owner, theFile.owner,
634 theFile.c_group, theFile.group,
635 (unsigned long) theFile.size,
636 timestrc, timestra, timestrm);
637#endif
638 /*@+usedef@*/
639
640 sh_error_handle (ShSuidchkSeverity, FIL__, __LINE__,
641 0, MSG_SUID_POLICY,
642 _("suid/sgid file not in database"),
643 tmp, msg );
644 SH_FREE(msg);
645
646 /* Quarantine file according to configured method
647 */
648 if (ShSuidchkQEnable == S_TRUE)
649 {
650 switch (ShSuidchkQMethod)
651 {
652 case SH_Q_DELETE:
653 /* if (unlink (theFile.fullpath) == -1) */
654 if (do_truncate (theFile.fullpath) == -1)
655 {
656 status = errno;
657 msg = SH_ALLOC(SH_BUFSIZE);
658 (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld"), status);
659 sh_error_handle (ShSuidchkSeverity,
660 FIL__, __LINE__,
661 status,
662 MSG_SUID_QREPORT, msg,
663 tmp );
664 SH_FREE(msg);
665 }
666 else
667 {
668 sh_error_handle (ShSuidchkSeverity,
669 FIL__, __LINE__, 0,
670 MSG_SUID_QREPORT,
671 _("Quarantine method applied"),
672 tmp );
673 }
674 break;
675 case SH_Q_CHANGEPERM:
676 cperm_status = 0;
677 file_d = -1;
678 if (retry_lstat(FIL__, __LINE__, tmpcat, &fileInfo) == -1)
679 {
680 status = errno;
681 msg = SH_ALLOC(SH_BUFSIZE);
682 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld"), status);
683 sh_error_handle (ShSuidchkSeverity,
684 FIL__, __LINE__,
685 status,
686 MSG_SUID_QREPORT, msg,
687 tmp );
688 SH_FREE(msg);
689 cperm_status = -1;
690 }
691
692 if (cperm_status == 0)
693 {
694 if (0 != (caperr = sl_get_cap_qdel()))
695 {
696 sh_error_handle((-1), FIL__, __LINE__,
697 caperr, MSG_E_SUBGEN,
698 sh_error_message (caperr),
699 _("sl_get_cap_qdel"));
700 cperm_status = -1;
701 }
702 }
703
704 if (cperm_status == 0)
705 {
706 file_d = aud_open (FIL__, __LINE__, SL_YESPRIV,
707 tmpcat, O_RDONLY, 0);
708 if (-1 == file_d)
709 {
710 status = errno;
711 msg = SH_ALLOC(SH_BUFSIZE);
712 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld"), status);
713 sh_error_handle (ShSuidchkSeverity,
714 FIL__, __LINE__,
715 status,
716 MSG_SUID_QREPORT, msg,
717 tmp );
718 SH_FREE(msg);
719 cperm_status = -1;
720 }
721 }
722
723 if (cperm_status == 0)
724 {
725 if (retry_fstat(FIL__, __LINE__, file_d, &fileInfo_F) == -1)
726 {
727 status = errno;
728 msg = SH_ALLOC(SH_BUFSIZE);
729 (void) sl_snprintf(msg, SH_BUFSIZE,
730 _("I/O error. errno = %ld"), status);
731 sh_error_handle (ShSuidchkSeverity,
732 FIL__, __LINE__,
733 status,
734 MSG_SUID_QREPORT, msg,
735 tmp );
736 SH_FREE(msg);
737 cperm_status = -1;
738 }
739 }
740
741 if (cperm_status == 0)
742 {
743 if (fileInfo_F.st_ino != fileInfo.st_ino ||
744 fileInfo_F.st_dev != fileInfo.st_dev ||
745 fileInfo_F.st_mode != fileInfo.st_mode)
746 {
747 status = errno;
748 msg = SH_ALLOC(SH_BUFSIZE);
749 (void) sl_snprintf(msg, SH_BUFSIZE,
750 _("Race detected. errno = %ld"), status);
751 sh_error_handle (ShSuidchkSeverity,
752 FIL__, __LINE__,
753 status,
754 MSG_SUID_QREPORT, msg,
755 tmp );
756 SH_FREE(msg);
757 cperm_status = -1;
758 }
759 }
760
761 if ((fileInfo.st_mode & S_ISUID) > 0)
762 fileInfo.st_mode -= S_ISUID;
763 if ((fileInfo.st_mode & S_ISGID) > 0)
764 fileInfo.st_mode -= S_ISGID;
765
766 if (cperm_status == 0)
767 {
768 if (fchmod(file_d, fileInfo.st_mode) == -1)
769 {
770 status = errno;
771 msg = SH_ALLOC(SH_BUFSIZE);
772 (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld"), status);
773 sh_error_handle (ShSuidchkSeverity,
774 FIL__, __LINE__,
775 status,
776 MSG_SUID_QREPORT,
777 msg, tmp );
778 SH_FREE(msg);
779 }
780 else
781 {
782 sh_error_handle (ShSuidchkSeverity,
783 FIL__, __LINE__,
784 0,
785 MSG_SUID_QREPORT,
786 _("Quarantine method applied"),
787 tmp );
788 }
789 }
790
791 if (0 != (caperr = sl_drop_cap_qdel()))
792 {
793 sh_error_handle((-1), FIL__, __LINE__,
794 caperr, MSG_E_SUBGEN,
795 sh_error_message (caperr),
796 _("sl_drop_cap_qdel"));
797 }
798
799 if (file_d != -1)
800 {
801 do {
802 status = close (file_d);
803 } while (status == -1 && errno == EINTR);
804
805 if (-1 == status)
806 {
807 status = errno;
808 msg = SH_ALLOC(SH_BUFSIZE);
809 (void) sl_snprintf(msg, SH_BUFSIZE,
810 _("I/O error. errno = %ld"), status);
811 sh_error_handle (ShSuidchkSeverity,
812 FIL__, __LINE__,
813 status,
814 MSG_SUID_QREPORT, msg,
815 tmp );
816 SH_FREE(msg);
817 cperm_status = -1;
818 }
819 }
820 break;
821 case SH_Q_MOVE:
822 dir = SH_ALLOC(PATH_MAX+1);
823 (void) sl_strlcpy (dir, DEFAULT_QDIR, PATH_MAX+1);
824 if (retry_stat (FIL__, __LINE__, dir, &fileInfo) != 0)
825 {
826 status = errno;
827 msg = SH_ALLOC(SH_BUFSIZE);
828 (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld (stat)"), status);
829 sh_error_handle (ShSuidchkSeverity,
830 FIL__, __LINE__,
831 status,
832 MSG_SUID_QREPORT, msg,
833 tmp );
834 SH_FREE(msg);
835 }
836 else
837 {
838 if (retry_lstat (FIL__, __LINE__,
839 theFile.fullpath, &fileInfo) == -1)
840 {
841 status = errno;
842 msg = SH_ALLOC(SH_BUFSIZE);
843 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld(stat)"), status);
844 sh_error_handle (ShSuidchkSeverity,
845 FIL__, __LINE__,
846 status,
847 MSG_SUID_QREPORT,
848 msg, tmp );
849 SH_FREE(msg);
850 }
851 else
852 {
853 basetmp = SH_ALLOC(1 + sl_strlen(theFile.fullpath));
854 (void) sl_strlcpy(basetmp, theFile.fullpath,
855 1 + sl_strlen(theFile.fullpath));
856 filetmp = SH_ALLOC(PATH_MAX+1);
857 (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s",
858 DEFAULT_QDIR, basename(basetmp));
859 SH_FREE(basetmp);
860
861 readFile = open (theFile.fullpath, O_RDONLY);
862 if (readFile != -1)
863 writeFile = open (filetmp, O_WRONLY|O_CREAT);
864
865 if ((readFile == -1) || (writeFile == -1))
866 {
867 status = errno;
868 msg = SH_ALLOC(SH_BUFSIZE);
869 (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld (open)"), status);
870 sh_error_handle (ShSuidchkSeverity,
871 FIL__, __LINE__, status,
872 MSG_SUID_QREPORT,
873 msg, tmp );
874 SH_FREE(msg);
875 }
876 else
877 {
878 /* sizeof(buffer) is 1024 */
879 while ((count = (int) read (readFile, buffer, sizeof (buffer))) > 0)
880 if ((int) write (writeFile, buffer, (size_t) count) != count)
881 {
882 status = errno;
883 msg = SH_ALLOC(SH_BUFSIZE);
884 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld (write)"), status);
885 sh_error_handle (ShSuidchkSeverity,
886 FIL__,
887 __LINE__,
888 status,
889 MSG_SUID_QREPORT,
890 msg, tmp );
891 SH_FREE(msg);
892 }
893 }
894 (void) close (readFile);
895 (void) fchmod(writeFile, S_IRUSR | S_IWUSR | S_IXUSR);
896 (void) close (writeFile);
897 /* if (unlink (theFile.fullpath) == -1) */
898 if (do_truncate (theFile.fullpath) == -1)
899 {
900 status = errno;
901 msg = SH_ALLOC(SH_BUFSIZE);
902 (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld"), status);
903 sh_error_handle (ShSuidchkSeverity,
904 FIL__, __LINE__, status,
905 MSG_SUID_QREPORT,
906 msg, tmp );
907 SH_FREE(msg);
908 }
909 else
910 {
911 (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s.info",
912 DEFAULT_QDIR,
913 basename(theFile.fullpath));
914 /*
915 * avoid chmod by setting umask
916 */
917 umask_old = umask (0077);
918 filePtr = fopen (filetmp, "w+");
919 /*@-usedef@*/
920 if (filePtr)
921 {
922 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"),
923 theFile.fullpath,
924 (unsigned long) theFile.size,
925 theFile.c_owner, (int) theFile.owner,
926 theFile.c_group, (int) theFile.group,
927 timestrc, timestra, timestrm);
928 (void) fclose (filePtr);
929 }
930 /*@+usedef@*/
931 umask (umask_old);
932
933 sh_error_handle (ShSuidchkSeverity,
934 FIL__,__LINE__,
935 0, MSG_SUID_QREPORT,
936 _("Quarantine method applied"),
937 tmp );
938 }
939 SH_FREE(filetmp);
940 }
941 }
942 SH_FREE(dir);
943 break;
944 default:
945 sh_error_handle (ShSuidchkSeverity, FIL__,
946 __LINE__, 0, MSG_SUID_QREPORT,
947 _("Bad quarantine method"),
948 tmp);
949 break;
950 }
951 }
952 else
953 {
954 /* 1.8.1 push file to in-memory database
955 */
956 (void) sh_hash_compdata (SH_LEVEL_READONLY,
957 &theFile, fileHash,
958 _("[SuidCheck]"),
959 ShSuidchkSeverity);
960 }
961 }
962 else
963 {
964 (void) sh_hash_compdata (SH_LEVEL_READONLY,
965 &theFile, fileHash,
966 _("[SuidCheck]"),
967 ShSuidchkSeverity);
968 }
969 }
970 }
971 SH_FREE(tmp);
972
973 }
974 }
975 SH_FREE(tmpcat);
976 }
977#ifdef HAVE_SCHED_YIELD
978 if (ShSuidchkYield == S_TRUE)
979 {
980 if (sched_yield() == -1)
981 {
982 status = errno;
983 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
984 _("Failed to release time slice"),
985 _("sh_suidchk_check_internal") );
986
987 }
988 }
989#endif
990 } while (thisEntry != NULL);
991
992 (void) closedir (thisDir);
993 SL_RETURN( (0), _("sh_suidchk_check_internal"));
994}
995
996/*************
997 *
998 * module init
999 *
1000 *************/
1001int sh_suidchk_init ()
1002{
1003 if (ShSuidchkActive == S_FALSE)
1004 return (-1);
1005
1006 return (0);
1007}
1008
1009
1010/*************
1011 *
1012 * module cleanup
1013 *
1014 *************/
1015int sh_suidchk_end ()
1016{
1017 return (0);
1018}
1019
1020
1021/*************
1022 *
1023 * module timer
1024 *
1025 *************/
1026int sh_suidchk_timer (time_t tcurrent)
1027{
1028 if (sh.flag.checkSum == SH_CHECK_INIT)
1029 return -1;
1030
1031 /* One-shot (not daemon and not loop forever)
1032 */
1033 if (sh.flag.isdaemon != S_TRUE && sh.flag.loop == S_FALSE)
1034 return -1;
1035
1036 if (ShSuidchkSched != NULL)
1037 {
1038 return test_sched(ShSuidchkSched);
1039 }
1040 if ((time_t) (tcurrent - lastcheck) >= ShSuidchkInterval)
1041 {
1042 lastcheck = tcurrent;
1043 return (-1);
1044 }
1045 return 0;
1046}
1047
1048/*************
1049 *
1050 * module check
1051 *
1052 *************/
1053
1054int sh_suidchk_check ()
1055{
1056 int status;
1057
1058 SL_ENTER(_("sh_suidchk_check"));
1059
1060 sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
1061 _("Checking for SUID programs"),
1062 _("suidchk_check") );
1063
1064 FileLimNow = time(NULL);
1065 FileLimStart = FileLimNow;
1066 FileLimNum = 0;
1067 FileLimTotal = 0;
1068
1069#ifdef SH_SUIDTESTDIR
1070 status = sh_suidchk_check_internal (SH_SUIDTESTDIR);
1071#else
1072 status = sh_suidchk_check_internal ("/");
1073#endif
1074
1075 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_SUID_SUMMARY,
1076 FileLimTotal,
1077 (long) (time(NULL) - FileLimStart) );
1078
1079 SL_RETURN(status, _("sh_suidchk_check"));
1080}
1081
1082/*************
1083 *
1084 * module setup
1085 *
1086 *************/
1087
1088int sh_suidchk_set_severity (char * c)
1089{
1090 int retval;
1091 char tmp[32];
1092
1093 SL_ENTER(_("sh_suidchk_set_severity"));
1094 tmp[0] = '='; tmp[1] = '\0';
1095 (void) sl_strlcat (tmp, c, 32);
1096 retval = sh_error_set_level (tmp, &ShSuidchkSeverity);
1097 SL_RETURN(retval, _("sh_suidchk_set_severity"));
1098}
1099
1100int sh_suidchk_set_exclude (char * c)
1101{
1102 SL_ENTER(_("sh_suidchk_set_exclude"));
1103 if (c == NULL || c[0] == '\0')
1104 {
1105 SL_RETURN(-1, _("sh_suidchk_set_exclude"));
1106 }
1107
1108 if (0 == sl_strncmp(c, _("NULL"), 4))
1109 {
1110 if (ShSuidchkExclude != NULL)
1111 SH_FREE(ShSuidchkExclude);
1112 ShSuidchkExclude = NULL;
1113 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1114 }
1115
1116 if (ShSuidchkExclude != NULL)
1117 SH_FREE(ShSuidchkExclude);
1118
1119 /* 1.8.1 add trailing slash
1120 */
1121 ExcludeLen = (int) sl_strlen(c);
1122 if (c[ExcludeLen-1] != '/')
1123 {
1124 ExcludeLen++;
1125 if ((ExcludeLen <= 0) || (ExcludeLen+1 <= 0)) /* may overflow */
1126 {
1127 SL_RETURN(-1, _("sh_suidchk_set_exclude"));
1128 }
1129 }
1130 ShSuidchkExclude = SH_ALLOC((size_t) ExcludeLen + 1);
1131 (void) sl_strlcpy(ShSuidchkExclude, c, (size_t)(ExcludeLen + 1));
1132 ShSuidchkExclude[ExcludeLen-1] = '/';
1133
1134 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1135}
1136
1137int sh_suidchk_set_timer (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 (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 (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 (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 (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 (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 (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 (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 if (NULL == hasmntopt(mnt, "nosuid"))
1779 type = mnt->mnt_type;
1780 else
1781 type = _("nosuid");
1782 }
1783 }
1784
1785 if (endmntent (mfp) == 0)
1786 {
1787 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1788 _("endmntent() failed"),
1789 _("filesystem_type_uncached") );
1790 }
1791#endif
1792
1793#ifdef FSTYPE_GETMNT /* Ultrix. */
1794 int offset = 0;
1795 struct fs_data fsd;
1796
1797 if (path == NULL || relpath == NULL)
1798 return NULL;
1799
1800 while (type == NULL
1801 && getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 0) > 0)
1802 {
1803 if (fsd.fd_req.dev == statp->st_dev)
1804 type = gt_names[fsd.fd_req.fstype];
1805 }
1806#endif
1807
1808#ifdef FSTYPE_USG_STATFS /* SVR3. */
1809 struct statfs fss;
1810 char typebuf[FSTYPSZ];
1811
1812 if (path == NULL || relpath == NULL)
1813 return NULL;
1814
1815 if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
1816 {
1817 /* Don't die if a file was just removed. */
1818 if (errno != ENOENT)
1819 {
1820 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1821 _("statfs() failed"),
1822 _("filesystem_type_uncached") );
1823 return NULL;
1824 }
1825 }
1826 else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
1827 type = typebuf;
1828#endif
1829
1830#ifdef FSTYPE_STATVFS /* SVR4. */
1831 struct statvfs fss;
1832
1833 if (path == NULL || relpath == NULL)
1834 return NULL;
1835
1836 if (statvfs (relpath, &fss) == -1)
1837 {
1838 /* Don't die if a file was just removed. */
1839 if (errno != ENOENT)
1840 {
1841 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1842 _("statvfs() failed"),
1843 _("filesystem_type_uncached") );
1844 return NULL;
1845 }
1846 }
1847 else
1848 {
1849 type = fss.f_basetype;
1850
1851 /* patch by Konstantin Khrooschev <nathoo@co.ru>
1852 */
1853 if( fss.f_flag & ST_NOSUID )
1854 type = _("nosuid");
1855 }
1856 (void) statp; /* fix compiler warning */
1857#endif
1858
1859#ifdef FSTYPE_STATFS /* 4.4BSD. */
1860 struct statfs fss;
1861 char *p;
1862#if defined(MNT_VISFLAGMASK) && defined(HAVE_STRUCT_STATFS_F_FLAGS)
1863 int flags;
1864#endif
1865 /* char * sh_dirname(const char *path); */
1866
1867 if (path == NULL || relpath == NULL)
1868 return NULL;
1869
1870 if (S_ISLNK (statp->st_mode))
1871 p = sh_dirname (relpath);
1872 else
1873 p = relpath;
1874
1875 if (statfs (p, &fss) == -1)
1876 {
1877 /* Don't die if symlink to nonexisting file, or a file that was
1878 just removed. */
1879 if (errno != ENOENT)
1880 {
1881 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1882 _("statfs() failed"),
1883 _("filesystem_type_uncached") );
1884 return NULL;
1885 }
1886 }
1887 else
1888 {
1889
1890#ifdef MFSNAMELEN /* NetBSD. */
1891 /* MEMORY LEAK !!!
1892 * type = sh_util_strdup (fss.f_fstypename);
1893 */
1894 sl_strlcpy (my_tmp_type, fss.f_fstypename, 64);
1895 type = my_tmp_type;
1896#else
1897 type = fstype_to_string (fss.f_type);
1898#endif
1899
1900#ifdef HAVE_STRUCT_STATFS_F_FLAGS
1901#ifdef MNT_VISFLAGMASK
1902 flags = fss.f_flags & MNT_VISFLAGMASK;
1903 if (flags & MNT_NOSUID)
1904#else
1905 if (fss.f_flags & MNT_NOSUID)
1906#endif
1907 type = _("nosuid");
1908#endif
1909 }
1910 if (p != relpath)
1911 SH_FREE (p);
1912#endif
1913
1914#ifdef AFS
1915 if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
1916 type = "afs";
1917#endif
1918
1919 /* An unknown value can be caused by an ENOENT error condition.
1920 Don't cache those values. */
1921 fstype_known = (int)(type != NULL);
1922
1923 return sh_util_strdup (type ? type : "unknown");
1924}
1925
1926#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
1927/* Return the value of the hexadecimal number represented by CP.
1928 No prefix (like '0x') or suffix (like 'h') is expected to be
1929 part of CP. */
1930
1931static int
1932xatoi (cp)
1933 char *cp;
1934{
1935 int val;
1936
1937 val = 0;
1938 while (*cp != '\0')
1939 {
1940 /*@+charint@*/
1941 if (*cp >= 'a' && *cp <= 'f')
1942 val = val * 16 + *cp - 'a' + 10;
1943 else if (*cp >= 'A' && *cp <= 'F')
1944 val = val * 16 + *cp - 'A' + 10;
1945 else if (*cp >= '0' && *cp <= '9')
1946 val = val * 16 + *cp - '0';
1947 else
1948 break;
1949 /*@-charint@*/
1950 cp++;
1951 }
1952 return val;
1953}
1954#endif
1955
1956
1957
1958#endif
1959
1960
1961/* #ifdef SH_USE_UTMP */
1962#endif
1963
1964
1965
Note: See TracBrowser for help on using the repository browser.