source: trunk/src/sh_suidchk.c@ 20

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

Rewrite of test suite, checksum for growing logs, fix for minor bug with dead client detection.

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