source: trunk/src/sh_suidchk.c@ 47

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

Code cleanup and minor fixes

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