source: trunk/src/sh_suidchk.c@ 33

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

Release candidate 3 for version 2.2.0

File size: 48.1 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2001 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <errno.h>
31#include <limits.h>
32#ifdef HAVE_LIBGEN_H
33#include <libgen.h>
34#endif
35#ifdef HAVE_SCHED_H
36#include <sched.h>
37#endif
38
39#ifdef SH_USE_SUIDCHK
40
41#ifndef HAVE_BASENAME
42#define basename(a) ((NULL == strrchr(a, '/')) ? (a) : (strrchr(a, '/')))
43#endif
44
45#undef FIL__
46#define FIL__ _("sh_suidchk.c")
47
48#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
49
50#if TIME_WITH_SYS_TIME
51#include <sys/time.h>
52#include <time.h>
53#else
54#if HAVE_SYS_TIME_H
55#include <sys/time.h>
56#else
57#include <time.h>
58#endif
59#endif
60
61#ifdef HAVE_DIRENT_H
62#include <dirent.h>
63#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
64#else
65#define dirent direct
66#define NAMLEN(dirent) (dirent)->d_namlen
67#ifdef HAVE_SYS_NDIR_H
68#include <sys/ndir.h>
69#endif
70#ifdef HAVE_SYS_DIR_H
71#include <sys/dir.h>
72#endif
73#ifdef HAVE_NDIR_H
74#include <ndir.h>
75#endif
76#endif
77
78#include "samhain.h"
79#include "sh_utils.h"
80#include "sh_error.h"
81#include "sh_modules.h"
82#include "sh_suidchk.h"
83#include "sh_hash.h"
84#include "sh_unix.h"
85#include "sh_files.h"
86#include "sh_schedule.h"
87#include "sh_calls.h"
88
89
90sh_rconf sh_suidchk_table[] = {
91 {
92 N_("severitysuidcheck"),
93 sh_suidchk_set_severity
94 },
95 {
96 N_("suidcheckactive"),
97 sh_suidchk_set_activate
98 },
99 {
100 N_("suidcheckinterval"),
101 sh_suidchk_set_timer
102 },
103 {
104 N_("suidcheckschedule"),
105 sh_suidchk_set_schedule
106 },
107 {
108 N_("suidcheckexclude"),
109 sh_suidchk_set_exclude
110 },
111 {
112 N_("suidcheckfps"),
113 sh_suidchk_set_fps
114 },
115 {
116 N_("suidcheckyield"),
117 sh_suidchk_set_yield
118 },
119 {
120 N_("suidcheckquarantinefiles"),
121 sh_suidchk_set_quarantine
122 },
123 {
124 N_("suidcheckquarantinemethod"),
125 sh_suidchk_set_qmethod
126 },
127 {
128 N_("suidcheckquarantinedelete"),
129 sh_suidchk_set_qdelete
130 },
131 {
132 NULL,
133 NULL
134 },
135};
136
137
138static time_t lastcheck = (time_t) 0;
139static int ShSuidchkActive = S_TRUE;
140static time_t ShSuidchkInterval = 7200;
141static long ShSuidchkFps = 0;
142static int ShSuidchkYield = S_FALSE;
143static int ShSuidchkQEnable = S_FALSE;
144static int ShSuidchkQMethod = SH_Q_CHANGEPERM;
145static int ShSuidchkQDelete = S_FALSE;
146static int ShSuidchkSeverity = SH_ERR_SEVERE;
147static char * ShSuidchkExclude = NULL;
148static int ExcludeLen = 0;
149
150static time_t FileLimNow = 0;
151static time_t FileLimStart = 0;
152static long FileLimNum = 0;
153static long FileLimTotal = 0;
154
155static sh_schedule_t * ShSuidchkSched = NULL;
156
157static char *
158filesystem_type (char * path, char * relpath, struct stat * statp);
159
160#ifndef PATH_MAX
161#define PATH_MAX 1024
162#endif
163
164extern unsigned long sh_files_maskof (int class);
165
166/* Recursively descend into the directory to make sure that
167 * there is no symlink in the path.
168 */
169static int do_truncate_int (char * path, int depth)
170{
171 char * q;
172 struct stat one;
173 struct stat two;
174 int fd;
175
176 if (depth > 99)
177 {
178 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
179 MSG_SUID_ERROR,
180 _("do_truncate: max depth 99 exceeded"));
181 return -1;
182 }
183 ++depth;
184 if (path[0] != '/')
185 {
186 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
187 MSG_SUID_ERROR,
188 _("do_truncate: not an absolute path"));
189 return -1;
190 }
191 ++path;
192 q = strchr(path, '/');
193 if (q)
194 {
195 *q = '\0';
196 if (0 != retry_lstat(FIL__, __LINE__, path, &one))
197 {
198 sh_error_handle ((-1), FIL__, __LINE__, errno,
199 MSG_SUID_ERROR,
200 sh_error_message(errno));
201 *q = '/';
202 return -1;
203 }
204 if (/*@-usedef@*/!S_ISDIR(one.st_mode)/*@+usedef@*/)
205
206 {
207 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
208 MSG_SUID_ERROR,
209 _("Possible race: not a directory"));
210 *q = '/';
211 return -1;
212 }
213
214
215 if (0 != chdir(path))
216 {
217 sh_error_handle ((-1), FIL__, __LINE__, errno,
218 MSG_SUID_ERROR,
219 sh_error_message(errno));
220 *q = '/';
221 return -1;
222 }
223 *q = '/';
224 if (0 != retry_lstat(FIL__, __LINE__, ".", &two))
225 {
226 sh_error_handle ((-1), FIL__, __LINE__, errno,
227 MSG_SUID_ERROR,
228 sh_error_message(errno));
229 return -1;
230 }
231 if (/*@-usedef@*/(one.st_dev != two.st_dev) ||
232 (one.st_ino != two.st_ino) ||
233 (!S_ISDIR(two.st_mode))/*@+usedef@*/)
234 {
235 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
236 MSG_SUID_ERROR,
237 _("Possible race: lstat(dir) != lstat(.)"));
238 return -1;
239 }
240
241
242 return (do_truncate_int(q, depth));
243 }
244 else
245 {
246 /* no more '/', so this is the file
247 */
248 if (*path == '\0')
249 return -1;
250 if (0 != retry_lstat(FIL__, __LINE__, path, &one))
251 {
252 sh_error_handle ((-1), FIL__, __LINE__, errno,
253 MSG_SUID_ERROR,
254 sh_error_message(errno));
255 return -1;
256 }
257 fd = open(path, O_RDWR);
258 if (-1 == fd)
259 {
260 sh_error_handle ((-1), FIL__, __LINE__, errno,
261 MSG_SUID_ERROR,
262 sh_error_message(errno));
263 return -1;
264 }
265 if (0 != retry_fstat(FIL__, __LINE__, fd, &two))
266 {
267 sh_error_handle ((-1), FIL__, __LINE__, errno,
268 MSG_SUID_ERROR,
269 sh_error_message(errno));
270 (void) close(fd);
271 return -1;
272 }
273 if (/*@-usedef@*/(one.st_dev != two.st_dev) ||
274 (one.st_ino != two.st_ino)/*@+usedef@*/)
275 {
276 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
277 MSG_SUID_ERROR,
278 _("Possible race: lstat != fstat"));
279 (void) close(fd);
280 return -1;
281 }
282 if (!S_ISREG(two.st_mode))
283 {
284 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
285 MSG_SUID_ERROR,
286 _("Possible race: not a regular file"));
287 (void) close(fd);
288 return -1;
289 }
290 if ((0 == (two.st_mode & S_ISUID)) && (0 == (two.st_mode & S_ISGID)))
291 {
292 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
293 MSG_SUID_ERROR,
294 _("Possible race: not a suid/sgid file"));
295 (void) close(fd);
296 return -1;
297 }
298 if (ShSuidchkQDelete == S_FALSE)
299 {
300 if ((two.st_mode & S_ISUID) > 0)
301 two.st_mode -= S_ISUID;
302 if ((two.st_mode & S_ISGID) > 0)
303 two.st_mode -= S_ISGID;
304#ifdef HAVE_FCHMOD
305 if (-1 == /*@-unrecog@*/fchmod(fd, two.st_mode)/*@+unrecog@*/)
306 {
307 sh_error_handle ((-1), FIL__, __LINE__, errno,
308 MSG_SUID_ERROR,
309 sh_error_message(errno));
310 (void) close(fd);
311 return -1;
312 }
313#else
314 sh_error_handle ((-1), FIL__, __LINE__, errno,
315 MSG_SUID_ERROR,
316 _("The fchmod() function is not available"));
317 (void) close(fd);
318 return -1;
319#endif
320 if (two.st_nlink > 1)
321 {
322 sh_error_handle ((-1), FIL__, __LINE__, 0,
323 MSG_SUID_ERROR,
324 _("Not truncated because hardlink count gt 1"));
325 (void) close(fd);
326 return -1;
327 }
328 /* The man page says: 'POSIX has ftruncate'
329 */
330 if (-1 == /*@-unrecog@*/ftruncate(fd, 0)/*@+unrecog@*/)
331 {
332 sh_error_handle ((-1), FIL__, __LINE__, errno,
333 MSG_SUID_ERROR,
334 sh_error_message(errno));
335 (void) close(fd);
336 return -1;
337 }
338 }
339 else
340 {
341 if (-1 == retry_aud_unlink(FIL__, __LINE__, path))
342 {
343 sh_error_handle ((-1), FIL__, __LINE__, errno,
344 MSG_SUID_ERROR,
345 sh_error_message(errno));
346 (void) close(fd);
347 return -1;
348 }
349 }
350 (void) close (fd);
351 return (0);
352 }
353}
354
355static int do_truncate (char * path)
356{
357 int caperr;
358 int result;
359
360 if (0 != chdir("/"))
361 {
362 sh_error_handle ((-1), FIL__, __LINE__, errno,
363 MSG_SUID_ERROR,
364 sh_error_message(errno));
365 }
366
367 if (0 != (caperr = sl_get_cap_qdel()))
368 {
369 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
370 sh_error_message (caperr),
371 _("sl_get_cap_qdel"));
372 }
373
374 result = do_truncate_int (path, 0);
375
376 if (0 != (caperr = sl_drop_cap_qdel()))
377 {
378 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
379 sh_error_message (caperr),
380 _("sl_drop_cap_qdel"));
381 }
382
383 if (0 != chdir("/"))
384 {
385 sh_error_handle ((-1), FIL__, __LINE__, errno,
386 MSG_SUID_ERROR,
387 sh_error_message(errno));
388 }
389 return result;
390}
391
392static
393int sh_suidchk_check_internal (char * iname)
394{
395 int caperr;
396 DIR * thisDir = NULL;
397 FILE * filePtr = NULL;
398 struct dirent * thisEntry;
399 char * tmpcat;
400 char * tmp;
401 char * msg;
402 char * dir;
403 char * filetmp;
404 char * basetmp;
405 char timestrc[32];
406 char timestra[32];
407 char timestrm[32];
408 char buffer[1024];
409 struct stat buf;
410 int status;
411 int count;
412 int readFile = -1;
413 int writeFile = -1;
414 char * fs;
415 long sl_status = SL_ENONE;
416 struct stat fileInfo;
417 struct stat fileInfo_F;
418 int file_d;
419
420 file_type theFile;
421 char fileHash[2*(KEY_LEN + 1)];
422
423 mode_t umask_old;
424 int cperm_status;
425
426 SL_ENTER(_("sh_suidchk_check_internal"));
427
428 if (iname == NULL)
429 {
430 TPT((0, FIL__, __LINE__ , _("msg=<directory name is NULL>\n")));
431 SL_RETURN( (-1), _("sh_suidchk_check_internal"));
432 }
433
434 if (sig_urgent > 0) {
435 SL_RETURN( (0), _("sh_suidchk_check_internal"));
436 }
437
438 thisDir = opendir (iname);
439
440 if (thisDir == NULL)
441 {
442 status = errno;
443 tmp = sh_util_safe_name(iname);
444 sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, status,
445 MSG_E_OPENDIR,
446 sh_error_message (status), tmp);
447 SH_FREE(tmp);
448 SL_RETURN( (-1), _("sh_suidchk_check_internal"));
449 }
450
451 do {
452
453 if (sig_urgent > 0) {
454 SL_RETURN( (0), _("sh_suidchk_check_internal"));
455 }
456
457
458 thisEntry = readdir (thisDir);
459
460 if (thisEntry != NULL) {
461
462 if (sl_strcmp (thisEntry->d_name, ".") == 0)
463 continue;
464
465 if (sl_strcmp (thisEntry->d_name, "..") == 0)
466 continue;
467
468 tmpcat = SH_ALLOC(PATH_MAX);
469 (void) sl_strlcpy(tmpcat, iname, PATH_MAX);
470
471 if ((sl_strlen(tmpcat) != sl_strlen(iname)) || (tmpcat[0] == '\0'))
472 sl_status = SL_ETRUNC;
473 else
474 {
475 if (tmpcat[1] != '\0')
476 sl_status = sl_strlcat(tmpcat, "/", PATH_MAX);
477 }
478 if (! SL_ISERROR(sl_status))
479 sl_status = sl_strlcat(tmpcat, thisEntry->d_name, PATH_MAX);
480 if (SL_ISERROR(sl_status))
481 {
482 tmp = sh_util_safe_name(tmpcat);
483 sh_error_handle ((-1), FIL__, __LINE__, (int) sl_status,
484 MSG_E_SUBGPATH,
485 _("path too long"),
486 _("sh_suidchk_check_internal"), tmp );
487 SH_FREE(tmp);
488 continue;
489 }
490
491 ++FileLimNum;
492 ++FileLimTotal;
493
494 if ((ShSuidchkFps > 0 && FileLimNum > ShSuidchkFps && FileLimTotal > 0)&&
495 (ShSuidchkYield == S_FALSE))
496 {
497 FileLimNum = 0;
498 FileLimNow = time(NULL);
499
500 if ( (FileLimNow - FileLimStart) > 0 &&
501 FileLimTotal/(FileLimNow - FileLimStart) > ShSuidchkFps )
502 (void) retry_msleep((int)((FileLimTotal/(FileLimNow-FileLimStart))/
503 ShSuidchkFps) , 0);
504 }
505
506 status = (int) retry_lstat(FIL__, __LINE__, tmpcat, &buf);
507
508 if (status != 0)
509 {
510 status = errno;
511 tmp = sh_util_safe_name(tmpcat);
512 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
513 sh_error_message(status),
514 tmpcat );
515 SH_FREE(tmp);
516 }
517 else
518 {
519 if (/*@-usedef@*/S_ISDIR(buf.st_mode)/*@+usedef@*/ &&
520 (ShSuidchkExclude == NULL ||
521 0 != strncmp(tmpcat, ShSuidchkExclude, (size_t) ExcludeLen)))
522 {
523 /* fs is a STATIC string
524 */
525 fs = filesystem_type (tmpcat, tmpcat, &buf);
526 if (fs != NULL
527#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_ALLOC(1 + sl_strlen(theFile.fullpath));
857 (void) sl_strlcpy(basetmp, theFile.fullpath,
858 1 + sl_strlen(theFile.fullpath));
859 filetmp = SH_ALLOC(PATH_MAX+1);
860 (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s",
861 DEFAULT_QDIR, basename(basetmp));
862 SH_FREE(basetmp);
863
864 readFile = open (theFile.fullpath, O_RDONLY);
865 if (readFile != -1)
866 writeFile = open (filetmp, O_WRONLY|O_CREAT);
867
868 if ((readFile == -1) || (writeFile == -1))
869 {
870 status = errno;
871 msg = SH_ALLOC(SH_BUFSIZE);
872 (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld (open)"), status);
873 sh_error_handle (ShSuidchkSeverity,
874 FIL__, __LINE__, status,
875 MSG_SUID_QREPORT,
876 msg, tmp );
877 SH_FREE(msg);
878 }
879 else
880 {
881 /* sizeof(buffer) is 1024 */
882 while ((count = (int) read (readFile, buffer, sizeof (buffer))) > 0)
883 if ((int) write (writeFile, buffer, (size_t) count) != count)
884 {
885 status = errno;
886 msg = SH_ALLOC(SH_BUFSIZE);
887 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld (write)"), status);
888 sh_error_handle (ShSuidchkSeverity,
889 FIL__,
890 __LINE__,
891 status,
892 MSG_SUID_QREPORT,
893 msg, tmp );
894 SH_FREE(msg);
895 }
896 }
897 (void) close (readFile);
898 (void) fchmod(writeFile, S_IRUSR | S_IWUSR | S_IXUSR);
899 (void) close (writeFile);
900 /* if (unlink (theFile.fullpath) == -1) */
901 if (do_truncate (theFile.fullpath) == -1)
902 {
903 status = errno;
904 msg = SH_ALLOC(SH_BUFSIZE);
905 (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld"), status);
906 sh_error_handle (ShSuidchkSeverity,
907 FIL__, __LINE__, status,
908 MSG_SUID_QREPORT,
909 msg, tmp );
910 SH_FREE(msg);
911 }
912 else
913 {
914 (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s.info",
915 DEFAULT_QDIR,
916 basename(theFile.fullpath));
917 /*
918 * avoid chmod by setting umask
919 */
920 umask_old = umask (0077);
921 filePtr = fopen (filetmp, "w+");
922 /*@-usedef@*/
923 if (filePtr)
924 {
925 fprintf(filePtr, _("File Info:\n filename=%s\n size=%lu\n owner=%s(%d)\n group=%s(%d)\n ctime=%s\n atime=%s\n mtime=%s\n"),
926 theFile.fullpath,
927 (unsigned long) theFile.size,
928 theFile.c_owner, (int) theFile.owner,
929 theFile.c_group, (int) theFile.group,
930 timestrc, timestra, timestrm);
931 (void) fclose (filePtr);
932 }
933 /*@+usedef@*/
934 umask (umask_old);
935
936 sh_error_handle (ShSuidchkSeverity,
937 FIL__,__LINE__,
938 0, MSG_SUID_QREPORT,
939 _("Quarantine method applied"),
940 tmp );
941 }
942 SH_FREE(filetmp);
943 }
944 }
945 SH_FREE(dir);
946 break;
947 default:
948 sh_error_handle (ShSuidchkSeverity, FIL__,
949 __LINE__, 0, MSG_SUID_QREPORT,
950 _("Bad quarantine method"),
951 tmp);
952 break;
953 }
954 }
955 else
956 {
957 /* 1.8.1 push file to in-memory database
958 */
959 (void) sh_hash_compdata (SH_LEVEL_READONLY,
960 &theFile, fileHash,
961 _("[SuidCheck]"),
962 ShSuidchkSeverity);
963 }
964 }
965 else
966 {
967 (void) sh_hash_compdata (SH_LEVEL_READONLY,
968 &theFile, fileHash,
969 _("[SuidCheck]"),
970 ShSuidchkSeverity);
971 }
972 }
973 }
974 SH_FREE(tmp);
975
976 }
977 }
978 SH_FREE(tmpcat);
979 }
980#ifdef HAVE_SCHED_YIELD
981 if (ShSuidchkYield == S_TRUE)
982 {
983 if (sched_yield() == -1)
984 {
985 status = errno;
986 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
987 _("Failed to release time slice"),
988 _("sh_suidchk_check_internal") );
989
990 }
991 }
992#endif
993 } while (thisEntry != NULL);
994
995 (void) closedir (thisDir);
996 SL_RETURN( (0), _("sh_suidchk_check_internal"));
997}
998
999/*************
1000 *
1001 * module init
1002 *
1003 *************/
1004int sh_suidchk_init ()
1005{
1006 if (ShSuidchkActive == S_FALSE)
1007 return (-1);
1008
1009 return (0);
1010}
1011
1012
1013/*************
1014 *
1015 * module cleanup
1016 *
1017 *************/
1018int sh_suidchk_end ()
1019{
1020 return (0);
1021}
1022
1023
1024/*************
1025 *
1026 * module timer
1027 *
1028 *************/
1029int sh_suidchk_timer (time_t tcurrent)
1030{
1031 if (sh.flag.checkSum == SH_CHECK_INIT)
1032 return -1;
1033
1034 /* One-shot (not daemon and not loop forever)
1035 */
1036 if (sh.flag.isdaemon != S_TRUE && sh.flag.loop == S_FALSE)
1037 return -1;
1038
1039 if (ShSuidchkSched != NULL)
1040 {
1041 return test_sched(ShSuidchkSched);
1042 }
1043 if ((time_t) (tcurrent - lastcheck) >= ShSuidchkInterval)
1044 {
1045 lastcheck = tcurrent;
1046 return (-1);
1047 }
1048 return 0;
1049}
1050
1051/*************
1052 *
1053 * module check
1054 *
1055 *************/
1056
1057int sh_suidchk_check ()
1058{
1059 int status;
1060
1061 SL_ENTER(_("sh_suidchk_check"));
1062
1063 sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
1064 _("Checking for SUID programs"),
1065 _("suidchk_check") );
1066
1067 FileLimNow = time(NULL);
1068 FileLimStart = FileLimNow;
1069 FileLimNum = 0;
1070 FileLimTotal = 0;
1071
1072#ifdef SH_SUIDTESTDIR
1073 status = sh_suidchk_check_internal (SH_SUIDTESTDIR);
1074#else
1075 status = sh_suidchk_check_internal ("/");
1076#endif
1077
1078 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_SUID_SUMMARY,
1079 FileLimTotal,
1080 (long) (time(NULL) - FileLimStart) );
1081
1082 SL_RETURN(status, _("sh_suidchk_check"));
1083}
1084
1085/*************
1086 *
1087 * module setup
1088 *
1089 *************/
1090
1091int sh_suidchk_set_severity (char * c)
1092{
1093 int retval;
1094 char tmp[32];
1095
1096 SL_ENTER(_("sh_suidchk_set_severity"));
1097 tmp[0] = '='; tmp[1] = '\0';
1098 (void) sl_strlcat (tmp, c, 32);
1099 retval = sh_error_set_level (tmp, &ShSuidchkSeverity);
1100 SL_RETURN(retval, _("sh_suidchk_set_severity"));
1101}
1102
1103int sh_suidchk_set_exclude (char * c)
1104{
1105 SL_ENTER(_("sh_suidchk_set_exclude"));
1106 if (c == NULL || c[0] == '\0')
1107 {
1108 SL_RETURN(-1, _("sh_suidchk_set_exclude"));
1109 }
1110
1111 if (0 == sl_strncmp(c, _("NULL"), 4))
1112 {
1113 if (ShSuidchkExclude != NULL)
1114 SH_FREE(ShSuidchkExclude);
1115 ShSuidchkExclude = NULL;
1116 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1117 }
1118
1119 if (ShSuidchkExclude != NULL)
1120 SH_FREE(ShSuidchkExclude);
1121
1122 /* 1.8.1 add trailing slash
1123 */
1124 ExcludeLen = (int) sl_strlen(c);
1125 if (c[ExcludeLen-1] != '/')
1126 {
1127 ExcludeLen++;
1128 if ((ExcludeLen <= 0) || (ExcludeLen+1 <= 0)) /* may overflow */
1129 {
1130 SL_RETURN(-1, _("sh_suidchk_set_exclude"));
1131 }
1132 }
1133 ShSuidchkExclude = SH_ALLOC((size_t) ExcludeLen + 1);
1134 (void) sl_strlcpy(ShSuidchkExclude, c, (size_t)(ExcludeLen + 1));
1135 ShSuidchkExclude[ExcludeLen-1] = '/';
1136
1137 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1138}
1139
1140int sh_suidchk_set_timer (char * c)
1141{
1142 long val;
1143
1144 SL_ENTER(_("sh_suidchk_set_timer"));
1145
1146 val = strtol (c, (char **)NULL, 10);
1147 if (val <= 0)
1148 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1149 _("suidchk timer"), c);
1150
1151 val = (val <= 0 ? 7200 : val);
1152
1153 ShSuidchkInterval = (time_t) val;
1154 SL_RETURN( 0, _("sh_suidchk_set_timer"));
1155}
1156
1157
1158int sh_suidchk_free_schedule ()
1159{
1160 sh_schedule_t * current = ShSuidchkSched;
1161 sh_schedule_t * next = NULL;
1162
1163 while (current != NULL)
1164 {
1165 next = current->next;
1166 SH_FREE(current);
1167 current = next;
1168 }
1169 ShSuidchkSched = NULL;
1170 return 0;
1171}
1172
1173int sh_suidchk_set_schedule (char * str)
1174{
1175 int status;
1176 sh_schedule_t * newSched = NULL;
1177
1178 SL_ENTER(_("sh_suidchk_set_schedule"));
1179
1180 /*
1181 if (ShSuidchkSched != NULL)
1182 {
1183 SH_FREE(ShSuidchkSched);
1184 ShSuidchkSched = NULL;
1185 }
1186 */
1187
1188 if (0 == sl_strncmp(str, _("NULL"), 4))
1189 {
1190 (void) sh_suidchk_free_schedule ();
1191 return 0;
1192 }
1193
1194 newSched = SH_ALLOC(sizeof(sh_schedule_t));
1195 status = create_sched(str, newSched);
1196 if (status != 0)
1197 {
1198 SH_FREE(newSched);
1199 newSched = NULL;
1200 }
1201 else
1202 {
1203 newSched->next = ShSuidchkSched;
1204 ShSuidchkSched = newSched;
1205 }
1206 SL_RETURN( status, _("sh_suidchk_set_schedule"));
1207}
1208
1209
1210
1211int sh_suidchk_set_fps (char * c)
1212{
1213 long val;
1214
1215 SL_ENTER(_("sh_suidchk_set_fps"));
1216
1217 val = strtol (c, (char **)NULL, 10);
1218 if (val < 0)
1219 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1220 _("suidchk fps"), c);
1221
1222 val = (val < 0 ? 0 : val);
1223
1224 ShSuidchkFps = val;
1225 SL_RETURN( 0, _("sh_suidchk_set_fps"));
1226}
1227
1228int sh_suidchk_set_yield (char * c)
1229{
1230 int i;
1231 SL_ENTER(_("sh_suidchk_set_yield"));
1232#ifdef HAVE_SCHED_YIELD
1233 i = sh_util_flagval(c, &ShSuidchkYield);
1234#else
1235 (void) c; /* cast to void to avoid compiler warning */
1236 i = -1;
1237#endif
1238 SL_RETURN(i, _("sh_suidchk_set_yield"));
1239}
1240
1241int sh_suidchk_set_activate (char * c)
1242{
1243 int i;
1244 SL_ENTER(_("sh_suidchk_set_activate"));
1245 i = sh_util_flagval(c, &ShSuidchkActive);
1246 SL_RETURN(i, _("sh_suidchk_set_activate"));
1247}
1248
1249int sh_suidchk_set_quarantine (char * c)
1250{
1251 int i;
1252 SL_ENTER(_("sh_suidchk_set_quarantine"));
1253 i = sh_util_flagval(c, &ShSuidchkQEnable);
1254 SL_RETURN(i, _("sh_suidchk_set_quarantine"));
1255}
1256
1257int sh_suidchk_set_qdelete (char * c)
1258{
1259 int i;
1260 SL_ENTER(_("sh_suidchk_set_qdelete"));
1261 i = sh_util_flagval(c, &ShSuidchkQDelete);
1262 SL_RETURN(i, _("sh_suidchk_set_qdelete"));
1263}
1264
1265int sh_suidchk_set_qmethod (char * c)
1266{
1267 long val;
1268 int ret = 0;
1269 struct stat buf;
1270
1271 SL_ENTER(_("sh_suidchk_set_qmethod"));
1272
1273 val = strtol (c, (char **)NULL, 10);
1274 if (val < 0)
1275 {
1276 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1277 _("suidchk qmethod"), c);
1278 ret = -1;
1279 }
1280 else
1281 {
1282 switch (val)
1283 {
1284 case SH_Q_DELETE:
1285 ShSuidchkQMethod = SH_Q_DELETE;
1286 break;
1287 case SH_Q_CHANGEPERM:
1288 ShSuidchkQMethod = SH_Q_CHANGEPERM;
1289 break;
1290 case SH_Q_MOVE:
1291 if (retry_stat (FIL__, __LINE__, DEFAULT_QDIR, &buf) != 0)
1292 {
1293 if (mkdir (DEFAULT_QDIR, 0750) == -1)
1294 {
1295 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
1296 MSG_SUID_ERROR,
1297 _("Unable to create quarantine directory"));
1298 }
1299 }
1300 ShSuidchkQMethod = SH_Q_MOVE;
1301 break;
1302 default:
1303 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1304 _("suidchk qmethod"), c);
1305 ShSuidchkQMethod = -1;
1306 ret = -1;
1307 break;
1308 }
1309 }
1310
1311 SL_RETURN( ret, _("sh_suidchk_set_qmethod"));
1312}
1313
1314#if defined(FSTYPE_STATFS) || defined(FSTYPE_AIX_STATFS)
1315/* dirname.c -- return all but the last element in a path
1316 Copyright (C) 1990 Free Software Foundation, Inc.
1317
1318 This program is free software; you can redistribute it and/or modify
1319 it under the terms of the GNU General Public License as published by
1320 the Free Software Foundation; either version 2, or (at your option)
1321 any later version.
1322
1323 This program is distributed in the hope that it will be useful,
1324 but WITHOUT ANY WARRANTY; without even the implied warranty of
1325 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1326 GNU General Public License for more details.
1327
1328 You should have received a copy of the GNU General Public License
1329 along with this program; if not, write to the Free Software Foundation,
1330 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
1331
1332/* Return the leading directories part of PATH,
1333 allocated with malloc. If out of memory, return 0.
1334 Assumes that trailing slashes have already been
1335 removed. */
1336
1337char * sh_dirname (const char * path)
1338{
1339 char *newpath;
1340 char *slash;
1341 int length; /* Length of result, not including NUL. */
1342
1343 slash = strrchr (path, '/');
1344 if (slash == NULL)
1345 {
1346 /* File is in the current directory. */
1347 path = ".";
1348 length = 1;
1349 }
1350 else
1351 {
1352 /* Remove any trailing slashes from the result. */
1353 while (slash > path && *slash == '/')
1354 --slash;
1355
1356 length = slash - path + 1;
1357 }
1358 newpath = (char *) SH_ALLOC (length + 1);
1359 if (newpath == NULL)
1360 return NULL;
1361 strncpy (newpath, path, length);
1362 newpath[length] = '\0';
1363 return newpath;
1364}
1365/* #ifdef FSTYPE_STATFS */
1366#endif
1367
1368/* fstype.c -- determine type of filesystems that files are on
1369 Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
1370
1371 This program is free software; you can redistribute it and/or modify
1372 it under the terms of the GNU General Public License as published by
1373 the Free Software Foundation; either version 2, or (at your option)
1374 any later version.
1375
1376 This program is distributed in the hope that it will be useful,
1377 but WITHOUT ANY WARRANTY; without even the implied warranty of
1378 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1379 GNU General Public License for more details.
1380
1381 You should have received a copy of the GNU General Public License
1382 along with this program; if not, write to the Free Software
1383 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
1384
1385/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
1386
1387/* Modified by R. Wichmann:
1388 - replaced error() by sh_error_handle()
1389 - replaced xstrdup() by sl_strdup()
1390 - replaced strstr() by sl_strstr()
1391 - some additions to recognize nosuid fs
1392*/
1393
1394/* modetype.h -- file type bits definitions for POSIX systems
1395 Requires sys/types.h sys/stat.h.
1396 Copyright (C) 1990 Free Software Foundation, Inc.
1397
1398 This program is free software; you can redistribute it and/or modify
1399 it under the terms of the GNU General Public License as published by
1400 the Free Software Foundation; either version 2, or (at your option)
1401 any later version.
1402
1403 This program is distributed in the hope that it will be useful,
1404 but WITHOUT ANY WARRANTY; without even the implied warranty of
1405 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1406 GNU General Public License for more details.
1407
1408 You should have received a copy of the GNU General Public License
1409 along with this program; if not, write to the Free Software
1410 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
1411
1412/* POSIX.1 doesn't mention the S_IFMT bits; instead, it uses S_IStype
1413 test macros. To make storing file types more convenient, define
1414 them; the values don't need to correspond to what the kernel uses,
1415 because of the way we use them. */
1416#ifndef S_IFMT /* Doesn't have traditional Unix macros. */
1417#define S_IFBLK 1
1418#define S_IFCHR 2
1419#define S_IFDIR 4
1420#define S_IFREG 8
1421#ifdef S_ISLNK
1422#define S_IFLNK 16
1423#endif
1424#ifdef S_ISFIFO
1425#define S_IFIFO 32
1426#endif
1427#ifdef S_ISSOCK
1428#define S_IFSOCK 64
1429#endif
1430#endif /* !S_IFMT */
1431
1432#ifdef STAT_MACROS_BROKEN
1433#undef S_ISBLK
1434#undef S_ISCHR
1435#undef S_ISDIR
1436#undef S_ISREG
1437#undef S_ISFIFO
1438#undef S_ISLNK
1439#undef S_ISSOCK
1440#undef S_ISMPB
1441#undef S_ISMPC
1442#undef S_ISNWK
1443#endif
1444
1445/* Do the reverse: define the POSIX.1 macros for traditional Unix systems
1446 that don't have them. */
1447#if !defined(S_ISBLK) && defined(S_IFBLK)
1448#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
1449#endif
1450#if !defined(S_ISCHR) && defined(S_IFCHR)
1451#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
1452#endif
1453#if !defined(S_ISDIR) && defined(S_IFDIR)
1454#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1455#endif
1456#if !defined(S_ISREG) && defined(S_IFREG)
1457#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1458#endif
1459#if !defined(S_ISFIFO) && defined(S_IFIFO)
1460#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
1461#endif
1462#if !defined(S_ISLNK) && defined(S_IFLNK)
1463#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1464#endif
1465#if !defined(S_ISSOCK) && defined(S_IFSOCK)
1466#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
1467#endif
1468#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
1469#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
1470#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
1471#endif
1472#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
1473#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
1474#endif
1475
1476
1477static char *filesystem_type_uncached (char *path, char *relpath,
1478 struct stat *statp);
1479
1480#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
1481static int xatoi (char *cp);
1482#endif
1483
1484#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
1485#include <mntent.h>
1486#if !defined(MOUNTED)
1487# if defined(MNT_MNTTAB) /* HP-UX. */
1488# define MOUNTED MNT_MNTTAB
1489# endif
1490# if defined(MNTTABNAME) /* Dynix. */
1491# define MOUNTED MNTTABNAME
1492# endif
1493#endif
1494#endif
1495
1496#ifdef FSTYPE_GETMNT /* Ultrix. */
1497#include <sys/param.h>
1498#include <sys/mount.h>
1499#include <sys/fs_types.h>
1500#endif
1501
1502#ifdef FSTYPE_USG_STATFS /* SVR3. */
1503#include <sys/statfs.h>
1504#include <sys/fstyp.h>
1505#endif
1506
1507#ifdef FSTYPE_STATVFS /* SVR4. */
1508#include <sys/statvfs.h>
1509#include <sys/fstyp.h>
1510#endif
1511
1512#ifdef FSTYPE_STATFS /* 4.4BSD. */
1513#include <sys/param.h> /* NetBSD needs this. */
1514#include <sys/mount.h>
1515
1516#ifndef MFSNAMELEN /* NetBSD defines this. */
1517static char *
1518fstype_to_string (t)
1519 short t;
1520{
1521#ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
1522 static char *mn[] = INITMOUNTNAMES;
1523 if (t >= 0 && t <= MOUNT_MAXTYPE)
1524 return mn[t];
1525 else
1526 return "?";
1527#else /* !INITMOUNTNAMES */
1528 switch (t)
1529 {
1530 case MOUNT_UFS:
1531 return _("ufs");
1532 case MOUNT_NFS:
1533 return _("nfs");
1534#ifdef MOUNT_PC
1535 case MOUNT_PC:
1536 return _("pc");
1537#endif
1538#ifdef MOUNT_MFS
1539 case MOUNT_MFS:
1540 return _("mfs");
1541#endif
1542#ifdef MOUNT_LO
1543 case MOUNT_LO:
1544 return _("lofs");
1545#endif
1546#ifdef MOUNT_TFS
1547 case MOUNT_TFS:
1548 return _("tfs");
1549#endif
1550#ifdef MOUNT_TMP
1551 case MOUNT_TMP:
1552 return _("tmp");
1553#endif
1554#ifdef MOUNT_MSDOS
1555 case MOUNT_MSDOS:
1556 return _("msdos");
1557#endif
1558#ifdef MOUNT_ISO9660
1559 case MOUNT_ISO9660:
1560 return _("iso9660fs");
1561#endif
1562 default:
1563 return "?";
1564 }
1565#endif /* !INITMOUNTNAMES */
1566}
1567#endif /* !MFSNAMELEN */
1568#endif /* FSTYPE_STATFS */
1569
1570#ifdef FSTYPE_AIX_STATFS /* AIX. */
1571#include <sys/vmount.h>
1572#include <sys/statfs.h>
1573
1574#define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
1575#define f_type f_vfstype
1576
1577static char *
1578fstype_to_string (t)
1579 short t;
1580{
1581 switch (t)
1582 {
1583 case MNT_AIX:
1584 return _("aix"); /* AIX 4.3: NFS filesystems are actually MNT_AIX. */
1585#ifdef MNT_NAMEFS
1586 case MNT_NAMEFS:
1587 return _("namefs");
1588#endif
1589 case MNT_NFS:
1590 return _("nfs");
1591 case MNT_JFS:
1592 return _("jfs");
1593 case MNT_CDROM:
1594 return _("cdrom");
1595#ifdef MNT_PROCFS
1596 case MNT_PROCFS:
1597 return _("procfs");
1598#endif
1599#ifdef MNT_SFS
1600 case MNT_SFS:
1601 return _("sfs");
1602#endif
1603#ifdef MNT_CACHEFS
1604 case MNT_CACHEFS:
1605 return _("cachefs");
1606#endif
1607#ifdef MNT_NFS3
1608 case MNT_NFS3:
1609 return _("nfs3");
1610#endif
1611#ifdef MNT_AUTOFS
1612 case MNT_AUTOFS:
1613 return _("autofs");
1614#endif
1615#ifdef MNT_VXFS
1616 case MNT_VXFS:
1617 return _("vxfs");
1618#endif
1619#ifdef MNT_VXODM
1620 case MNT_VXODM:
1621 return _("veritasfs");
1622#endif
1623#ifdef MNT_UDF
1624 case MNT_UDF:
1625 return _("udfs");
1626#endif
1627#ifdef MNT_NFS4
1628 case MNT_NFS4:
1629 return _("nfs4");
1630#endif
1631#ifdef MNT_RFS4
1632 case MNT_RFS4:
1633 return _("nfs4");
1634#endif
1635#ifdef MNT_CIFS
1636 case MNT_CIFS:
1637 return _("cifs");
1638#endif
1639 default:
1640 return "?";
1641 }
1642}
1643#endif /* FSTYPE_AIX_STATFS */
1644
1645#ifdef AFS
1646#include <netinet/in.h>
1647#include <afs/venus.h>
1648#if __STDC__
1649/* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
1650#undef _VICEIOCTL
1651#define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
1652#endif
1653#ifndef _IOW
1654/* AFS on Solaris 2.3 doesn't get this definition. */
1655#include <sys/ioccom.h>
1656#endif
1657
1658static int
1659in_afs (path)
1660 char *path;
1661{
1662 static char space[2048];
1663 struct ViceIoctl vi;
1664
1665 vi.in_size = 0;
1666 vi.out_size = sizeof (space);
1667 vi.out = space;
1668
1669 if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
1670 && (errno == EINVAL || errno == ENOENT))
1671 return 0;
1672 return 1;
1673}
1674#endif /* AFS */
1675
1676/* Nonzero if the current filesystem's type is known. */
1677static int fstype_known = 0;
1678
1679/* Return a static string naming the type of filesystem that the file PATH,
1680 described by STATP, is on.
1681 RELPATH is the file name relative to the current directory.
1682 Return "unknown" if its filesystem type is unknown. */
1683
1684static char *
1685filesystem_type (char * path, char * relpath, struct stat * statp)
1686{
1687 static char *current_fstype = NULL;
1688 static dev_t current_dev;
1689
1690 if (current_fstype != NULL)
1691 {
1692 if ((0 != fstype_known) && statp->st_dev == current_dev)
1693 return current_fstype; /* Cached value. */
1694 SH_FREE (current_fstype);
1695 }
1696 current_dev = statp->st_dev;
1697 current_fstype = filesystem_type_uncached (path, relpath, statp);
1698 return current_fstype;
1699}
1700
1701/* Return a newly allocated string naming the type of filesystem that the
1702 file PATH, described by STATP, is on.
1703 RELPATH is the file name relative to the current directory.
1704 Return "unknown" if its filesystem type is unknown. */
1705
1706static char *
1707filesystem_type_uncached (path, relpath, statp)
1708 char *path;
1709 char *relpath;
1710 struct stat *statp;
1711{
1712 char * type = NULL;
1713#ifdef MFSNAMELEN /* NetBSD. */
1714 static char my_tmp_type[64];
1715#endif
1716
1717#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
1718 char *table = MOUNTED;
1719 FILE *mfp;
1720 struct mntent *mnt;
1721
1722 if (path == NULL || relpath == NULL)
1723 return NULL;
1724
1725 mfp = setmntent (table, "r");
1726 if (mfp == NULL)
1727 {
1728 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1729 _("setmntent() failed"),
1730 _("filesystem_type_uncached") );
1731 return NULL;
1732 }
1733
1734 /* Find the entry with the same device number as STATP, and return
1735 that entry's fstype. */
1736 while (type == NULL && (mnt = getmntent (mfp)) != NULL)
1737 {
1738 char *devopt;
1739 dev_t dev;
1740 struct stat disk_stats;
1741
1742#ifdef MNTTYPE_IGNORE
1743 if (0 == strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
1744 continue;
1745#endif
1746
1747 /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
1748 in the options string. For older systems, we need to stat the
1749 directory that the filesystem is mounted on to get it.
1750
1751 Unfortunately, the HPUX 9.x mnttab entries created by automountq
1752 contain a dev= option but the option value does not match the
1753 st_dev value of the file (maybe the lower 16 bits match?). */
1754
1755#if !defined(hpux) && !defined(__hpux__)
1756 devopt = sl_strstr (mnt->mnt_opts, "dev=");
1757 if (devopt)
1758 {
1759 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
1760 dev = (dev_t) xatoi (devopt + 6);
1761 else
1762 dev = (dev_t) xatoi (devopt + 4);
1763 }
1764 else
1765#endif /* not hpux */
1766 {
1767 if (stat (mnt->mnt_dir, &disk_stats) == -1)
1768 {
1769 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1770 _("stat() failed"),
1771 _("filesystem_type_uncached") );
1772 return NULL;
1773 }
1774 dev = disk_stats.st_dev;
1775 }
1776
1777 if (dev == statp->st_dev)
1778 {
1779 /* check for the "nosuid" option
1780 */
1781 if (NULL == hasmntopt(mnt, "nosuid"))
1782 type = mnt->mnt_type;
1783 else
1784 type = _("nosuid");
1785 }
1786 }
1787
1788 if (endmntent (mfp) == 0)
1789 {
1790 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1791 _("endmntent() failed"),
1792 _("filesystem_type_uncached") );
1793 }
1794#endif
1795
1796#ifdef FSTYPE_GETMNT /* Ultrix. */
1797 int offset = 0;
1798 struct fs_data fsd;
1799
1800 if (path == NULL || relpath == NULL)
1801 return NULL;
1802
1803 while (type == NULL
1804 && getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 0) > 0)
1805 {
1806 if (fsd.fd_req.dev == statp->st_dev)
1807 type = gt_names[fsd.fd_req.fstype];
1808 }
1809#endif
1810
1811#ifdef FSTYPE_USG_STATFS /* SVR3. */
1812 struct statfs fss;
1813 char typebuf[FSTYPSZ];
1814
1815 if (path == NULL || relpath == NULL)
1816 return NULL;
1817
1818 if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
1819 {
1820 /* Don't die if a file was just removed. */
1821 if (errno != ENOENT)
1822 {
1823 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1824 _("statfs() failed"),
1825 _("filesystem_type_uncached") );
1826 return NULL;
1827 }
1828 }
1829 else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
1830 type = typebuf;
1831#endif
1832
1833#ifdef FSTYPE_STATVFS /* SVR4. */
1834 struct statvfs fss;
1835
1836 if (path == NULL || relpath == NULL)
1837 return NULL;
1838
1839 if (statvfs (relpath, &fss) == -1)
1840 {
1841 /* Don't die if a file was just removed. */
1842 if (errno != ENOENT)
1843 {
1844 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1845 _("statvfs() failed"),
1846 _("filesystem_type_uncached") );
1847 return NULL;
1848 }
1849 }
1850 else
1851 {
1852 type = fss.f_basetype;
1853
1854 /* patch by Konstantin Khrooschev <nathoo@co.ru>
1855 */
1856 if( fss.f_flag & ST_NOSUID )
1857 type = _("nosuid");
1858 }
1859 (void) statp; /* fix compiler warning */
1860#endif
1861
1862#ifdef FSTYPE_STATFS /* 4.4BSD. */
1863 struct statfs fss;
1864 char *p;
1865#if defined(MNT_VISFLAGMASK) && defined(HAVE_STRUCT_STATFS_F_FLAGS)
1866 int flags;
1867#endif
1868 /* char * sh_dirname(const char *path); */
1869
1870 if (path == NULL || relpath == NULL)
1871 return NULL;
1872
1873 if (S_ISLNK (statp->st_mode))
1874 p = sh_dirname (relpath);
1875 else
1876 p = relpath;
1877
1878 if (statfs (p, &fss) == -1)
1879 {
1880 /* Don't die if symlink to nonexisting file, or a file that was
1881 just removed. */
1882 if (errno != ENOENT)
1883 {
1884 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1885 _("statfs() failed"),
1886 _("filesystem_type_uncached") );
1887 return NULL;
1888 }
1889 }
1890 else
1891 {
1892
1893#ifdef MFSNAMELEN /* NetBSD. */
1894 /* MEMORY LEAK !!!
1895 * type = sh_util_strdup (fss.f_fstypename);
1896 */
1897 sl_strlcpy (my_tmp_type, fss.f_fstypename, 64);
1898 type = my_tmp_type;
1899#else
1900 type = fstype_to_string (fss.f_type);
1901#endif
1902
1903#ifdef HAVE_STRUCT_STATFS_F_FLAGS
1904#ifdef MNT_VISFLAGMASK
1905 flags = fss.f_flags & MNT_VISFLAGMASK;
1906 if (flags & MNT_NOSUID)
1907#else
1908 if (fss.f_flags & MNT_NOSUID)
1909#endif
1910 type = _("nosuid");
1911#endif
1912 }
1913 if (p != relpath)
1914 SH_FREE (p);
1915#endif
1916
1917#ifdef AFS
1918 if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
1919 type = "afs";
1920#endif
1921
1922 /* An unknown value can be caused by an ENOENT error condition.
1923 Don't cache those values. */
1924 fstype_known = (int)(type != NULL);
1925
1926 return sh_util_strdup (type ? type : "unknown");
1927}
1928
1929#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
1930/* Return the value of the hexadecimal number represented by CP.
1931 No prefix (like '0x') or suffix (like 'h') is expected to be
1932 part of CP. */
1933
1934static int
1935xatoi (cp)
1936 char *cp;
1937{
1938 int val;
1939
1940 val = 0;
1941 while (*cp != '\0')
1942 {
1943 /*@+charint@*/
1944 if (*cp >= 'a' && *cp <= 'f')
1945 val = val * 16 + *cp - 'a' + 10;
1946 else if (*cp >= 'A' && *cp <= 'F')
1947 val = val * 16 + *cp - 'A' + 10;
1948 else if (*cp >= '0' && *cp <= '9')
1949 val = val * 16 + *cp - '0';
1950 else
1951 break;
1952 /*@-charint@*/
1953 cp++;
1954 }
1955 return val;
1956}
1957#endif
1958
1959
1960
1961#endif
1962
1963
1964/* #ifdef SH_USE_UTMP */
1965#endif
1966
1967
1968
Note: See TracBrowser for help on using the repository browser.