source: trunk/src/sh_suidchk.c@ 246

Last change on this file since 246 was 231, checked in by katerina, 16 years ago

Recognize fdesc filesystem on MacOS X for suid check (ticket #153).

File size: 52.8 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
33#ifdef HAVE_SCHED_H
34#include <sched.h>
35#endif
36
37#ifdef SH_USE_SUIDCHK
38
39#undef FIL__
40#define FIL__ _("sh_suidchk.c")
41
42#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
43
44#if TIME_WITH_SYS_TIME
45#include <sys/time.h>
46#include <time.h>
47#else
48#if HAVE_SYS_TIME_H
49#include <sys/time.h>
50#else
51#include <time.h>
52#endif
53#endif
54
55#ifdef HAVE_DIRENT_H
56#include <dirent.h>
57#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
58#else
59#define dirent direct
60#define NAMLEN(dirent) (dirent)->d_namlen
61#ifdef HAVE_SYS_NDIR_H
62#include <sys/ndir.h>
63#endif
64#ifdef HAVE_SYS_DIR_H
65#include <sys/dir.h>
66#endif
67#ifdef HAVE_NDIR_H
68#include <ndir.h>
69#endif
70#endif
71#define NEED_ADD_DIRENT
72
73#include "samhain.h"
74#include "sh_pthread.h"
75#include "sh_utils.h"
76#include "sh_error.h"
77#include "sh_modules.h"
78#include "sh_suidchk.h"
79#include "sh_hash.h"
80#include "sh_unix.h"
81#include "sh_files.h"
82#include "sh_schedule.h"
83#include "sh_calls.h"
84
85
86sh_rconf sh_suidchk_table[] = {
87 {
88 N_("severitysuidcheck"),
89 sh_suidchk_set_severity
90 },
91 {
92 N_("suidcheckactive"),
93 sh_suidchk_set_activate
94 },
95 {
96 N_("suidcheckinterval"),
97 sh_suidchk_set_timer
98 },
99 {
100 N_("suidcheckschedule"),
101 sh_suidchk_set_schedule
102 },
103 {
104 N_("suidcheckexclude"),
105 sh_suidchk_set_exclude
106 },
107 {
108 N_("suidcheckfps"),
109 sh_suidchk_set_fps
110 },
111 {
112 N_("suidcheckyield"),
113 sh_suidchk_set_yield
114 },
115 {
116 N_("suidchecknosuid"),
117 sh_suidchk_set_nosuid
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 ShSuidchkNosuid = S_FALSE;
143static int ShSuidchkYield = S_FALSE;
144static int ShSuidchkQEnable = S_FALSE;
145static int ShSuidchkQMethod = SH_Q_CHANGEPERM;
146static int ShSuidchkQDelete = S_FALSE;
147static int ShSuidchkSeverity = SH_ERR_SEVERE;
148static char * ShSuidchkExclude = NULL;
149static size_t ExcludeLen = 0;
150
151static time_t FileLimNow = 0;
152static time_t FileLimStart = 0;
153static long FileLimNum = 0;
154static long FileLimTotal = 0;
155
156static sh_schedule_t * ShSuidchkSched = NULL;
157
158static char *
159filesystem_type (char * path, char * relpath, struct stat * statp);
160
161#ifndef PATH_MAX
162#define PATH_MAX 1024
163#endif
164
165extern unsigned long sh_files_maskof (int class);
166
167static void set_defaults (void)
168{
169 ShSuidchkActive = S_TRUE;
170 ShSuidchkInterval = 7200;
171 ShSuidchkFps = 0;
172 ShSuidchkNosuid = S_FALSE;
173 ShSuidchkYield = S_FALSE;
174 ShSuidchkQEnable = S_FALSE;
175 ShSuidchkQMethod = SH_Q_CHANGEPERM;
176 ShSuidchkQDelete = S_FALSE;
177 ShSuidchkSeverity = SH_ERR_SEVERE;
178 if (ShSuidchkExclude != NULL)
179 SH_FREE(ShSuidchkExclude);
180 ShSuidchkExclude = NULL;
181 ExcludeLen = 0;
182
183 FileLimNow = 0;
184 FileLimStart = 0;
185 FileLimNum = 0;
186 FileLimTotal = 0;
187
188 return;
189}
190
191/* Recursively descend into the directory to make sure that
192 * there is no symlink in the path.
193 */
194static int do_truncate_int (char * path, int depth)
195{
196 char * q;
197 struct stat one;
198 struct stat two;
199 int fd;
200 char errbuf[SH_ERRBUF_SIZE];
201
202 if (depth > 99)
203 {
204 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
205 MSG_SUID_ERROR,
206 _("do_truncate: max depth 99 exceeded"));
207 return -1;
208 }
209 ++depth;
210 if (path[0] != '/')
211 {
212 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
213 MSG_SUID_ERROR,
214 _("do_truncate: not an absolute path"));
215 return -1;
216 }
217 ++path;
218 q = strchr(path, '/');
219 if (q)
220 {
221 *q = '\0';
222 if (0 != retry_lstat(FIL__, __LINE__, path, &one))
223 {
224 sh_error_handle ((-1), FIL__, __LINE__, errno,
225 MSG_SUID_ERROR,
226 sh_error_message(errno, errbuf, sizeof(errbuf)));
227 *q = '/';
228 return -1;
229 }
230 if (/*@-usedef@*/!S_ISDIR(one.st_mode)/*@+usedef@*/)
231
232 {
233 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
234 MSG_SUID_ERROR,
235 _("Possible race: not a directory"));
236 *q = '/';
237 return -1;
238 }
239
240
241 if (0 != chdir(path))
242 {
243 sh_error_handle ((-1), FIL__, __LINE__, errno,
244 MSG_SUID_ERROR,
245 sh_error_message(errno, errbuf, sizeof(errbuf)));
246 *q = '/';
247 return -1;
248 }
249 *q = '/';
250 if (0 != retry_lstat(FIL__, __LINE__, ".", &two))
251 {
252 sh_error_handle ((-1), FIL__, __LINE__, errno,
253 MSG_SUID_ERROR,
254 sh_error_message(errno, errbuf, sizeof(errbuf)));
255 return -1;
256 }
257 if (/*@-usedef@*/(one.st_dev != two.st_dev) ||
258 (one.st_ino != two.st_ino) ||
259 (!S_ISDIR(two.st_mode))/*@+usedef@*/)
260 {
261 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
262 MSG_SUID_ERROR,
263 _("Possible race: lstat(dir) != lstat(.)"));
264 return -1;
265 }
266
267
268 return (do_truncate_int(q, depth));
269 }
270 else
271 {
272 /* no more '/', so this is the file
273 */
274 if (*path == '\0')
275 return -1;
276 if (0 != retry_lstat(FIL__, __LINE__, path, &one))
277 {
278 sh_error_handle ((-1), FIL__, __LINE__, errno,
279 MSG_SUID_ERROR,
280 sh_error_message(errno, errbuf, sizeof(errbuf)));
281 return -1;
282 }
283 fd = open(path, O_RDWR);
284 if (-1 == fd)
285 {
286 sh_error_handle ((-1), FIL__, __LINE__, errno,
287 MSG_SUID_ERROR,
288 sh_error_message(errno, errbuf, sizeof(errbuf)));
289 return -1;
290 }
291 if (0 != retry_fstat(FIL__, __LINE__, fd, &two))
292 {
293 sh_error_handle ((-1), FIL__, __LINE__, errno,
294 MSG_SUID_ERROR,
295 sh_error_message(errno, errbuf, sizeof(errbuf)));
296 (void) close(fd);
297 return -1;
298 }
299 if (/*@-usedef@*/(one.st_dev != two.st_dev) ||
300 (one.st_ino != two.st_ino)/*@+usedef@*/)
301 {
302 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
303 MSG_SUID_ERROR,
304 _("Possible race: lstat != fstat"));
305 (void) close(fd);
306 return -1;
307 }
308 if (!S_ISREG(two.st_mode))
309 {
310 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
311 MSG_SUID_ERROR,
312 _("Possible race: not a regular file"));
313 (void) close(fd);
314 return -1;
315 }
316 if ((0 == (two.st_mode & S_ISUID)) && (0 == (two.st_mode & S_ISGID)))
317 {
318 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
319 MSG_SUID_ERROR,
320 _("Possible race: not a suid/sgid file"));
321 (void) close(fd);
322 return -1;
323 }
324 if (ShSuidchkQDelete == S_FALSE)
325 {
326 if ((two.st_mode & S_ISUID) > 0)
327 two.st_mode -= S_ISUID;
328 if ((two.st_mode & S_ISGID) > 0)
329 two.st_mode -= S_ISGID;
330#ifdef HAVE_FCHMOD
331 if (-1 == /*@-unrecog@*/fchmod(fd, two.st_mode)/*@+unrecog@*/)
332 {
333 sh_error_handle ((-1), FIL__, __LINE__, errno,
334 MSG_SUID_ERROR,
335 sh_error_message(errno, errbuf, sizeof(errbuf)));
336 (void) close(fd);
337 return -1;
338 }
339#else
340 sh_error_handle ((-1), FIL__, __LINE__, errno,
341 MSG_SUID_ERROR,
342 _("The fchmod() function is not available"));
343 (void) close(fd);
344 return -1;
345#endif
346 if (two.st_nlink > 1)
347 {
348 sh_error_handle ((-1), FIL__, __LINE__, 0,
349 MSG_SUID_ERROR,
350 _("Not truncated because hardlink count gt 1"));
351 (void) close(fd);
352 return -1;
353 }
354 /* The man page says: 'POSIX has ftruncate'
355 */
356 if (-1 == /*@-unrecog@*/ftruncate(fd, 0)/*@+unrecog@*/)
357 {
358 sh_error_handle ((-1), FIL__, __LINE__, errno,
359 MSG_SUID_ERROR,
360 sh_error_message(errno, errbuf, sizeof(errbuf)));
361 (void) close(fd);
362 return -1;
363 }
364 }
365 else
366 {
367 if (-1 == retry_aud_unlink(FIL__, __LINE__, path))
368 {
369 sh_error_handle ((-1), FIL__, __LINE__, errno,
370 MSG_SUID_ERROR,
371 sh_error_message(errno, errbuf, sizeof(errbuf)));
372 (void) close(fd);
373 return -1;
374 }
375 }
376 (void) close (fd);
377 return (0);
378 }
379}
380
381static int do_truncate (const char * path_in)
382{
383 int caperr;
384 int result;
385 char * path;
386 char errbuf[SH_ERRBUF_SIZE];
387
388 if (0 != chdir("/"))
389 {
390 sh_error_handle ((-1), FIL__, __LINE__, errno,
391 MSG_SUID_ERROR,
392 sh_error_message(errno, errbuf, sizeof(errbuf)));
393 }
394
395 if (0 != (caperr = sl_get_cap_qdel()))
396 {
397 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
398 sh_error_message (caperr, errbuf, sizeof(errbuf)),
399 _("sl_get_cap_qdel"));
400 }
401
402 path = sh_util_strdup (path_in);
403 result = do_truncate_int (path, 0);
404 SH_FREE(path);
405
406 if (0 != (caperr = sl_drop_cap_qdel()))
407 {
408 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
409 sh_error_message (caperr, errbuf, sizeof(errbuf)),
410 _("sl_drop_cap_qdel"));
411 }
412
413 if (0 != chdir("/"))
414 {
415 sh_error_handle ((-1), FIL__, __LINE__, errno,
416 MSG_SUID_ERROR,
417 sh_error_message(errno, errbuf, sizeof(errbuf)));
418 }
419 return result;
420}
421
422static void sh_q_delete(const char * fullpath)
423{
424 int status;
425 char * msg;
426 char * tmp;
427
428 if (do_truncate (fullpath) == -1)
429 {
430 status = errno;
431 msg = SH_ALLOC(SH_BUFSIZE);
432 tmp = sh_util_safe_name(fullpath);
433
434 (void) sl_snprintf(msg, SH_BUFSIZE,
435 _("Problem quarantining file. File NOT quarantined. errno = %ld"),
436 status);
437 sh_error_handle (ShSuidchkSeverity,
438 FIL__, __LINE__,
439 status,
440 MSG_SUID_QREPORT, msg,
441 tmp );
442 SH_FREE(tmp);
443 SH_FREE(msg);
444 }
445 else
446 {
447 tmp = sh_util_safe_name(fullpath);
448 sh_error_handle (ShSuidchkSeverity,
449 FIL__, __LINE__, 0,
450 MSG_SUID_QREPORT,
451 _("Quarantine method applied"),
452 tmp );
453 SH_FREE(tmp);
454 }
455 return;
456}
457
458static void sh_q_move(const char * fullpath, file_type * theFile,
459 const char * timestrc, const char * timestra,
460 const char * timestrm)
461{
462 int status;
463 int readFile = -1;
464 int writeFile = -1;;
465 struct stat fileInfo;
466 ssize_t count;
467 char * msg;
468 char * tmp;
469 char * basetmp;
470 char * filetmp;
471 char buffer[1024];
472 char * dir = SH_ALLOC(PATH_MAX+1);
473 mode_t umask_old;
474 FILE * filePtr = NULL;
475
476 (void) sl_strlcpy (dir, DEFAULT_QDIR, PATH_MAX+1);
477
478 if (retry_stat (FIL__, __LINE__, dir, &fileInfo) != 0)
479 {
480 /* Quarantine directory does not exist,
481 */
482 status = errno;
483 msg = SH_ALLOC(SH_BUFSIZE);
484 tmp = sh_util_safe_name(fullpath);
485
486 (void) sl_snprintf(msg, SH_BUFSIZE,
487 _("Problem quarantining file. File NOT quarantined. errno = %ld (stat)"),
488 status);
489 sh_error_handle (ShSuidchkSeverity,
490 FIL__, __LINE__,
491 status,
492 MSG_SUID_QREPORT, msg,
493 tmp );
494 SH_FREE(tmp);
495 SH_FREE(msg);
496 }
497 else
498 {
499 if (retry_lstat (FIL__, __LINE__,
500 fullpath, &fileInfo) == -1)
501 {
502 status = errno;
503 msg = SH_ALLOC(SH_BUFSIZE);
504 tmp = sh_util_safe_name(fullpath);
505
506 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld(stat)"), status);
507 sh_error_handle (ShSuidchkSeverity,
508 FIL__, __LINE__,
509 status,
510 MSG_SUID_QREPORT,
511 msg, tmp );
512 SH_FREE(tmp);
513 SH_FREE(msg);
514 }
515 else
516 {
517 basetmp = sh_util_strdup(fullpath);
518 filetmp = SH_ALLOC(PATH_MAX+1);
519 tmp = sh_util_basename(basetmp);
520
521 (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s",
522 DEFAULT_QDIR, tmp);
523 SH_FREE(tmp);
524 SH_FREE(basetmp);
525
526 readFile = open (fullpath, O_RDONLY);
527 if (readFile != -1)
528 writeFile = open (filetmp, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IXUSR);
529
530 if ((readFile == -1) || (writeFile == -1))
531 {
532 status = errno;
533 msg = SH_ALLOC(SH_BUFSIZE);
534 tmp = sh_util_safe_name(fullpath);
535
536 (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld (open)"), status);
537 sh_error_handle (ShSuidchkSeverity,
538 FIL__, __LINE__, status,
539 MSG_SUID_QREPORT,
540 msg, tmp );
541 SH_FREE(tmp);
542 SH_FREE(msg);
543 }
544 else
545 {
546 /* sizeof(buffer) is 1024
547 */
548 while ((count = (int) read (readFile, buffer, sizeof (buffer))) > 0)
549 {
550 if ((int) write (writeFile, buffer, (size_t) count) != count)
551 {
552 status = errno;
553 msg = SH_ALLOC(SH_BUFSIZE);
554 tmp = sh_util_safe_name(fullpath);
555
556 (void) sl_snprintf(msg, SH_BUFSIZE,
557 _("I/O error. errno = %ld (write)"), status);
558 sh_error_handle (ShSuidchkSeverity,
559 FIL__,
560 __LINE__,
561 status,
562 MSG_SUID_QREPORT,
563 msg, tmp );
564 SH_FREE(tmp);
565 SH_FREE(msg);
566 }
567 }
568 }
569
570 (void) close (readFile);
571 (void) fchmod(writeFile, S_IRUSR | S_IWUSR | S_IXUSR);
572 (void) close (writeFile);
573
574 if (do_truncate (fullpath) == -1)
575 {
576 status = errno;
577 msg = SH_ALLOC(SH_BUFSIZE);
578 tmp = sh_util_safe_name(fullpath);
579
580 (void) sl_snprintf(msg, SH_BUFSIZE,
581 _("Problem quarantining file. File NOT quarantined. errno = %ld"),
582 status);
583 sh_error_handle (ShSuidchkSeverity,
584 FIL__, __LINE__, status,
585 MSG_SUID_QREPORT,
586 msg, tmp );
587 SH_FREE(tmp);
588 SH_FREE(msg);
589 }
590 else
591 {
592 tmp = sh_util_basename(fullpath);
593
594 (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s.info",
595 DEFAULT_QDIR,
596 tmp);
597
598 SH_FREE(tmp);
599 /*
600 * avoid chmod by setting umask
601 */
602 umask_old = umask (0077);
603 filePtr = fopen (filetmp, "w+");
604
605 /*@-usedef@*/
606 if (filePtr)
607 {
608 fprintf(filePtr,
609 _("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"),
610 fullpath,
611 (unsigned long) theFile->size,
612 theFile->c_owner, (int) theFile->owner,
613 theFile->c_group, (int) theFile->group,
614 timestrc, timestra, timestrm);
615 (void) fclose (filePtr);
616 }
617 /*@+usedef@*/
618 umask (umask_old);
619
620 tmp = sh_util_safe_name(fullpath);
621 sh_error_handle (ShSuidchkSeverity,
622 FIL__,__LINE__,
623 0, MSG_SUID_QREPORT,
624 _("Quarantine method applied"),
625 tmp );
626 SH_FREE(tmp);
627 }
628 SH_FREE(filetmp);
629 }
630 }
631 SH_FREE(dir);
632 return;
633}
634
635static void sh_q_changeperm(const char * fullpath)
636{
637 int caperr;
638 int status;
639 char * msg;
640 char * tmp;
641 struct stat fileInfo;
642 struct stat fileInfo_F;
643 int cperm_status = 0;
644 int file_d = -1;
645 char errbuf[SH_ERRBUF_SIZE];
646
647 if (retry_lstat(FIL__, __LINE__, fullpath, &fileInfo) == -1)
648 {
649 status = errno;
650 msg = SH_ALLOC(SH_BUFSIZE);
651 tmp = sh_util_safe_name(fullpath);
652
653 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld"), status);
654 sh_error_handle (ShSuidchkSeverity,
655 FIL__, __LINE__,
656 status,
657 MSG_SUID_QREPORT, msg,
658 tmp );
659 SH_FREE(tmp);
660 SH_FREE(msg);
661 cperm_status = -1;
662 }
663
664 if (cperm_status == 0)
665 {
666 if (0 != (caperr = sl_get_cap_qdel()))
667 {
668 sh_error_handle((-1), FIL__, __LINE__,
669 caperr, MSG_E_SUBGEN,
670 sh_error_message (caperr, errbuf, sizeof(errbuf)),
671 _("sl_get_cap_qdel"));
672 cperm_status = -1;
673 }
674 }
675
676 if (cperm_status == 0)
677 {
678 file_d = aud_open (FIL__, __LINE__, SL_YESPRIV,
679 fullpath, O_RDONLY, 0);
680 if (-1 == file_d)
681 {
682 status = errno;
683 msg = SH_ALLOC(SH_BUFSIZE);
684 tmp = sh_util_safe_name(fullpath);
685
686 (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld"), status);
687 sh_error_handle (ShSuidchkSeverity,
688 FIL__, __LINE__,
689 status,
690 MSG_SUID_QREPORT, msg,
691 tmp );
692 SH_FREE(tmp);
693 SH_FREE(msg);
694 cperm_status = -1;
695 }
696 }
697
698 if (cperm_status == 0)
699 {
700 if (retry_fstat(FIL__, __LINE__, file_d, &fileInfo_F) == -1)
701 {
702 status = errno;
703 msg = SH_ALLOC(SH_BUFSIZE);
704 tmp = sh_util_safe_name(fullpath);
705
706 (void) sl_snprintf(msg, SH_BUFSIZE,
707 _("I/O error. errno = %ld"), status);
708 sh_error_handle (ShSuidchkSeverity,
709 FIL__, __LINE__,
710 status,
711 MSG_SUID_QREPORT, msg,
712 tmp );
713 SH_FREE(tmp);
714 SH_FREE(msg);
715 cperm_status = -1;
716 }
717 }
718
719 if (cperm_status == 0)
720 {
721 if (fileInfo_F.st_ino != fileInfo.st_ino ||
722 fileInfo_F.st_dev != fileInfo.st_dev ||
723 fileInfo_F.st_mode != fileInfo.st_mode)
724 {
725 status = errno;
726 msg = SH_ALLOC(SH_BUFSIZE);
727 tmp = sh_util_safe_name(fullpath);
728
729 (void) sl_snprintf(msg, SH_BUFSIZE,
730 _("Race detected. errno = %ld"), status);
731 sh_error_handle (ShSuidchkSeverity,
732 FIL__, __LINE__,
733 status,
734 MSG_SUID_QREPORT, msg,
735 tmp );
736 SH_FREE(tmp);
737 SH_FREE(msg);
738 cperm_status = -1;
739 }
740 }
741
742 if ((fileInfo.st_mode & S_ISUID) > 0)
743 fileInfo.st_mode -= S_ISUID;
744 if ((fileInfo.st_mode & S_ISGID) > 0)
745 fileInfo.st_mode -= S_ISGID;
746
747 if (cperm_status == 0)
748 {
749 if (fchmod(file_d, fileInfo.st_mode) == -1)
750 {
751 status = errno;
752 msg = SH_ALLOC(SH_BUFSIZE);
753 tmp = sh_util_safe_name(fullpath);
754
755 (void) sl_snprintf(msg, SH_BUFSIZE,
756 _("Problem quarantining file. File NOT quarantined. errno = %ld"),
757 status);
758 sh_error_handle (ShSuidchkSeverity,
759 FIL__, __LINE__,
760 status,
761 MSG_SUID_QREPORT,
762 msg, tmp );
763 SH_FREE(tmp);
764 SH_FREE(msg);
765 }
766 else
767 {
768 tmp = sh_util_safe_name(fullpath);
769 sh_error_handle (ShSuidchkSeverity,
770 FIL__, __LINE__,
771 0,
772 MSG_SUID_QREPORT,
773 _("Quarantine method applied"),
774 tmp );
775 SH_FREE(tmp);
776 }
777 }
778
779 if (0 != (caperr = sl_drop_cap_qdel()))
780 {
781 sh_error_handle((-1), FIL__, __LINE__,
782 caperr, MSG_E_SUBGEN,
783 sh_error_message (caperr, errbuf, sizeof(errbuf)),
784 _("sl_drop_cap_qdel"));
785 }
786
787 if (file_d != -1)
788 {
789 do {
790 status = close (file_d);
791 } while (status == -1 && errno == EINTR);
792
793 if (-1 == status)
794 {
795 status = errno;
796 msg = SH_ALLOC(SH_BUFSIZE);
797 tmp = sh_util_safe_name(fullpath);
798
799 (void) sl_snprintf(msg, SH_BUFSIZE,
800 _("I/O error. errno = %ld"), status);
801 sh_error_handle (ShSuidchkSeverity,
802 FIL__, __LINE__,
803 status,
804 MSG_SUID_QREPORT, msg,
805 tmp );
806 SH_FREE(tmp);
807 SH_FREE(msg);
808 cperm_status = -1;
809 }
810 }
811 return;
812}
813
814static void report_file (const char * tmpcat, file_type * theFile,
815 char * timestrc, char * timestra, char * timestrm)
816{
817 char * msg = SH_ALLOC(SH_BUFSIZE);
818 char * tmp = sh_util_safe_name(tmpcat);
819
820 msg[0] = '\0';
821 /*@-usedef@*/
822
823#ifdef SH_USE_XML
824 (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\""),
825 theFile->c_owner, theFile->owner,
826 theFile->c_group, theFile->group,
827 (unsigned long) theFile->size,
828 timestrc, timestra, timestrm);
829#else
830 (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>"),
831 theFile->c_owner, theFile->owner,
832 theFile->c_group, theFile->group,
833 (unsigned long) theFile->size,
834 timestrc, timestra, timestrm);
835#endif
836 /*@+usedef@*/
837
838 sh_error_handle (ShSuidchkSeverity, FIL__, __LINE__,
839 0, MSG_SUID_POLICY,
840 _("suid/sgid file not in database"),
841 tmp, msg );
842 SH_FREE(tmp);
843 SH_FREE(msg);
844 return;
845}
846
847static
848int sh_suidchk_check_internal (char * iname)
849{
850 DIR * thisDir = NULL;
851 struct dirent * thisEntry;
852 char * tmpcat;
853 char * tmp;
854 char timestrc[32];
855 char timestra[32];
856 char timestrm[32];
857 struct stat buf;
858 int status;
859 int fflags;
860 char * fs;
861 long sl_status;
862 file_type * theFile = NULL;
863 char fileHash[2*(KEY_LEN + 1)];
864
865 struct sh_dirent * dirlist;
866 struct sh_dirent * dirlist_orig;
867 char errbuf[SH_ERRBUF_SIZE];
868
869 SL_ENTER(_("sh_suidchk_check_internal"));
870
871 if (iname == NULL)
872 {
873 TPT((0, FIL__, __LINE__ , _("msg=<directory name is NULL>\n")));
874 SL_RETURN( (-1), _("sh_suidchk_check_internal"));
875 }
876
877 if (sig_urgent > 0) {
878 SL_RETURN( (0), _("sh_suidchk_check_internal"));
879 }
880
881 thisDir = opendir (iname);
882
883 if (thisDir == NULL)
884 {
885 status = errno;
886 tmp = sh_util_safe_name(iname);
887 sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, status,
888 MSG_E_OPENDIR,
889 sh_error_message (status, errbuf, sizeof(errbuf)), tmp);
890 SH_FREE(tmp);
891 SL_RETURN( (-1), _("sh_suidchk_check_internal"));
892 }
893
894 /* Loop over directory entries
895 */
896 SH_MUTEX_LOCK(mutex_readdir);
897
898 dirlist = NULL;
899 dirlist_orig = NULL;
900
901 do {
902
903 thisEntry = readdir (thisDir);
904
905 if (thisEntry != NULL) {
906
907 if (sl_strcmp (thisEntry->d_name, ".") == 0)
908 continue;
909
910 if (sl_strcmp (thisEntry->d_name, "..") == 0)
911 continue;
912
913 dirlist = addto_sh_dirlist (thisEntry, dirlist);
914 }
915
916 } while (thisEntry != NULL);
917
918 SH_MUTEX_UNLOCK(mutex_readdir);
919
920 closedir(thisDir);
921
922 dirlist_orig = dirlist;
923
924 sl_status = SL_ENONE;
925
926 do {
927
928 /* If the directory is empty, dirlist = NULL
929 */
930 if (!dirlist)
931 break;
932
933 if (sig_urgent > 0) {
934 SL_RETURN( (0), _("sh_suidchk_check_internal"));
935 }
936
937 tmpcat = SH_ALLOC(PATH_MAX);
938 (void) sl_strlcpy(tmpcat, iname, PATH_MAX);
939
940 if ((sl_strlen(tmpcat) != sl_strlen(iname)) || (tmpcat[0] == '\0'))
941 {
942 sl_status = SL_ETRUNC;
943 }
944 else
945 {
946 if (tmpcat[1] != '\0')
947 sl_status = sl_strlcat(tmpcat, "/", PATH_MAX);
948 }
949
950 if (! SL_ISERROR(sl_status))
951 sl_status = sl_strlcat(tmpcat, dirlist->sh_d_name, PATH_MAX);
952
953 if (SL_ISERROR(sl_status))
954 {
955 tmp = sh_util_safe_name(tmpcat);
956 sh_error_handle ((-1), FIL__, __LINE__, (int) sl_status,
957 MSG_E_SUBGPATH,
958 _("path too long"),
959 _("sh_suidchk_check_internal"), tmp );
960 SH_FREE(tmp);
961 SH_FREE(tmpcat);
962 dirlist = dirlist->next;
963 continue;
964 }
965
966 ++FileLimNum;
967 ++FileLimTotal;
968
969 /* Rate limit (Fps == Files per second)
970 */
971 if ((ShSuidchkFps > 0 && FileLimNum > ShSuidchkFps && FileLimTotal > 0)&&
972 (ShSuidchkYield == S_FALSE))
973 {
974 FileLimNum = 0;
975 FileLimNow = time(NULL);
976
977 if ( (FileLimNow - FileLimStart) > 0 &&
978 FileLimTotal/(FileLimNow - FileLimStart) > ShSuidchkFps )
979 (void) retry_msleep((int)((FileLimTotal/(FileLimNow-FileLimStart))/
980 ShSuidchkFps) , 0);
981 }
982
983 status = (int) retry_lstat(FIL__, __LINE__, tmpcat, &buf);
984
985 if (status != 0)
986 {
987 status = errno;
988 tmp = sh_util_safe_name(tmpcat);
989 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
990 sh_error_message(status, errbuf, sizeof(errbuf)),
991 tmpcat );
992 SH_FREE(tmp);
993 }
994 else
995 {
996 if (/*@-usedef@*/S_ISDIR(buf.st_mode)/*@+usedef@*/ &&
997 (ShSuidchkExclude == NULL ||
998 0 != strcmp(tmpcat, ShSuidchkExclude)))
999 {
1000 /* fs is a STATIC string or NULL
1001 */
1002 fs = filesystem_type (tmpcat, tmpcat, &buf);
1003 if (fs != NULL
1004#ifndef SH_SUIDTESTDIR
1005 &&
1006 0 != strncmp (_("afs"), fs, 3) &&
1007 0 != strncmp (_("devfs"), fs, 5) &&
1008 0 != strncmp (_("fdesc"), fs, 5) &&
1009 0 != strncmp (_("iso9660"), fs, 7) &&
1010 0 != strncmp (_("cd9660"), fs, 6) &&
1011 0 != strncmp (_("lustre"), fs, 6) &&
1012 0 != strncmp (_("mmfs"), fs, 4) &&
1013 0 != strncmp (_("msdos"), fs, 5) &&
1014 0 != strncmp (_("nfs"), fs, 3) &&
1015 0 != strncmp (_("proc"), fs, 4) &&
1016 0 != strncmp (_("sysfs"), fs, 5) &&
1017 0 != strncmp (_("vfat"), fs, 4)
1018#endif
1019 )
1020 {
1021 if ((ShSuidchkNosuid == S_TRUE) ||
1022 (0 != strncmp (_("nosuid"), fs, 6)))
1023 /* fprintf(stderr, "%s: %s\n", fs, tmpcat); */
1024 (void) sh_suidchk_check_internal(tmpcat);
1025 }
1026 }
1027 else if (S_ISREG(buf.st_mode) &&
1028 (0 !=(S_ISUID & buf.st_mode) ||
1029#if defined(HOST_IS_LINUX)
1030 (0 !=(S_ISGID & buf.st_mode) &&
1031 0 !=(S_IXGRP & buf.st_mode))
1032#else
1033 0 !=(S_ISGID & buf.st_mode)
1034#endif
1035 )
1036 )
1037 {
1038 theFile = SH_ALLOC(sizeof(file_type));
1039
1040 (void) sl_strlcpy (theFile->fullpath, tmpcat, PATH_MAX);
1041 theFile->check_mask = sh_files_maskof(SH_LEVEL_READONLY);
1042 CLEAR_SH_FFLAG_REPORTED(theFile->file_reported);
1043 theFile->attr_string = NULL;
1044 theFile->link_path = NULL;
1045
1046 status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO],
1047 dirlist->sh_d_name,
1048 theFile, fileHash, 0);
1049
1050 tmp = sh_util_safe_name(tmpcat);
1051
1052 if (status != 0)
1053 {
1054 sh_error_handle (ShSuidchkSeverity, FIL__, __LINE__,
1055 0, MSG_E_SUBGPATH,
1056 _("Could not check suid/sgid file"),
1057 _("sh_suidchk_check_internal"),
1058 tmp);
1059 }
1060 else
1061 {
1062
1063 if ( sh.flag.update == S_TRUE &&
1064 (sh.flag.checkSum == SH_CHECK_INIT ||
1065 sh.flag.checkSum == SH_CHECK_CHECK))
1066 {
1067 /* Updating database. Report new files that
1068 * are not in database already. Then compare
1069 * to database and report changes.
1070 */
1071 if (-1 == sh_hash_have_it (tmpcat))
1072 {
1073 sh_error_handle ((-1), FIL__, __LINE__,
1074 0, MSG_SUID_FOUND, tmp );
1075 }
1076 else
1077 {
1078 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
1079 0, MSG_SUID_FOUND, tmp );
1080 }
1081
1082 if (0 == sh_hash_compdata (SH_LEVEL_READONLY,
1083 theFile, fileHash,
1084 _("[SuidCheck]"),
1085 ShSuidchkSeverity))
1086 {
1087 sh_hash_pushdata_memory (theFile, fileHash);
1088 }
1089
1090 sh_hash_addflag(tmpcat, SH_FFLAG_SUIDCHK);
1091
1092 }
1093
1094 else if (sh.flag.checkSum == SH_CHECK_INIT &&
1095 sh.flag.update == S_FALSE )
1096 {
1097 /* Running init. Report on files detected.
1098 */
1099 sh_hash_pushdata (theFile, fileHash);
1100 sh_error_handle ((-1), FIL__, __LINE__,
1101 0, MSG_SUID_FOUND, tmp );
1102 }
1103
1104 else if (sh.flag.checkSum == SH_CHECK_CHECK )
1105 {
1106 /* Running file check. Report on new files
1107 * detected, and quarantine them.
1108 */
1109 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
1110 0, MSG_SUID_FOUND, tmp );
1111
1112 fflags = sh_hash_getflags(tmpcat);
1113
1114 if ( (-1 == fflags) || (!SH_FFLAG_SUIDCHK_SET(fflags)))
1115 {
1116 if (-1 == fflags)
1117 {
1118 (void) sh_unix_gmttime (theFile->ctime, timestrc, sizeof(timestrc));
1119 (void) sh_unix_gmttime (theFile->atime, timestra, sizeof(timestra));
1120 (void) sh_unix_gmttime (theFile->mtime, timestrm, sizeof(timestrm));
1121
1122 report_file(tmpcat, theFile, timestrc, timestra, timestrm);
1123 }
1124 /* Quarantine file according to configured method
1125 */
1126 if (ShSuidchkQEnable == S_TRUE)
1127 {
1128 switch (ShSuidchkQMethod)
1129 {
1130 case SH_Q_DELETE:
1131 sh_q_delete(theFile->fullpath);
1132 break;
1133 case SH_Q_CHANGEPERM:
1134 sh_q_changeperm(theFile->fullpath);
1135 break;
1136 case SH_Q_MOVE:
1137 sh_q_move(theFile->fullpath, theFile, timestrc, timestra, timestrm);
1138 break;
1139 default:
1140 sh_error_handle (ShSuidchkSeverity, FIL__,
1141 __LINE__, 0, MSG_SUID_QREPORT,
1142 _("Bad quarantine method"), tmp);
1143 break;
1144 }
1145 }
1146 else
1147 {
1148 /* 1.8.1 push file to in-memory database
1149 */
1150 (void) sh_hash_compdata (SH_LEVEL_READONLY,
1151 theFile, fileHash,
1152 _("[SuidCheck]"),
1153 ShSuidchkSeverity);
1154
1155 sh_hash_addflag(tmpcat, SH_FFLAG_SUIDCHK);
1156
1157 }
1158 }
1159 else
1160 {
1161 /* File exists. Check for modifications.
1162 */
1163 (void) sh_hash_compdata (SH_LEVEL_READONLY,
1164 theFile, fileHash,
1165 _("[SuidCheck]"),
1166 ShSuidchkSeverity);
1167
1168 sh_hash_addflag(tmpcat, SH_FFLAG_SUIDCHK);
1169
1170 }
1171 }
1172 }
1173 SH_FREE(tmp);
1174 if (theFile->attr_string) SH_FREE(theFile->attr_string);
1175 if (theFile->link_path) SH_FREE(theFile->link_path);
1176 SH_FREE(theFile);
1177 }
1178 }
1179 SH_FREE(tmpcat);
1180
1181
1182#ifdef HAVE_SCHED_YIELD
1183 if (ShSuidchkYield == S_TRUE)
1184 {
1185 if (sched_yield() == -1)
1186 {
1187 status = errno;
1188 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1189 _("Failed to release time slice"),
1190 _("sh_suidchk_check_internal") );
1191 }
1192 }
1193#endif
1194
1195 dirlist = dirlist->next;
1196
1197 } while (dirlist != NULL);
1198
1199
1200 kill_sh_dirlist (dirlist_orig);
1201
1202 SL_RETURN( (0), _("sh_suidchk_check_internal"));
1203}
1204
1205/*************
1206 *
1207 * module init
1208 *
1209 *************/
1210int sh_suidchk_init (struct mod_type * arg)
1211{
1212 (void) arg;
1213 if (ShSuidchkActive == S_FALSE)
1214 return (-1);
1215
1216 return (0);
1217}
1218
1219
1220/*************
1221 *
1222 * module cleanup
1223 *
1224 *************/
1225int sh_suidchk_end ()
1226{
1227 return (0);
1228}
1229
1230
1231/*************
1232 *
1233 * module timer
1234 *
1235 *************/
1236int sh_suidchk_timer (time_t tcurrent)
1237{
1238 if (sh.flag.checkSum == SH_CHECK_INIT)
1239 return -1;
1240
1241 /* One-shot (not daemon and not loop forever)
1242 */
1243 if (sh.flag.isdaemon != S_TRUE && sh.flag.loop == S_FALSE)
1244 return -1;
1245
1246 if (ShSuidchkSched != NULL)
1247 {
1248 return test_sched(ShSuidchkSched);
1249 }
1250 if ((time_t) (tcurrent - lastcheck) >= ShSuidchkInterval)
1251 {
1252 lastcheck = tcurrent;
1253 return (-1);
1254 }
1255 return 0;
1256}
1257
1258/*************
1259 *
1260 * module check
1261 *
1262 *************/
1263
1264int sh_suidchk_check ()
1265{
1266 int status;
1267
1268 SL_ENTER(_("sh_suidchk_check"));
1269
1270 sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
1271 _("Checking for SUID programs"),
1272 _("suidchk_check") );
1273
1274 FileLimNow = time(NULL);
1275 FileLimStart = FileLimNow;
1276 FileLimNum = 0;
1277 FileLimTotal = 0;
1278
1279#ifdef SH_SUIDTESTDIR
1280 status = sh_suidchk_check_internal (SH_SUIDTESTDIR);
1281#else
1282 status = sh_suidchk_check_internal ("/");
1283#endif
1284
1285 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_SUID_SUMMARY,
1286 FileLimTotal,
1287 (long) (time(NULL) - FileLimStart) );
1288
1289 SL_RETURN(status, _("sh_suidchk_check"));
1290}
1291
1292/*************
1293 *
1294 * module setup
1295 *
1296 *************/
1297
1298int sh_suidchk_set_severity (const char * c)
1299{
1300 int retval;
1301 char tmp[32];
1302
1303 SL_ENTER(_("sh_suidchk_set_severity"));
1304 tmp[0] = '='; tmp[1] = '\0';
1305 (void) sl_strlcat (tmp, c, 32);
1306 retval = sh_error_set_level (tmp, &ShSuidchkSeverity);
1307 SL_RETURN(retval, _("sh_suidchk_set_severity"));
1308}
1309
1310int sh_suidchk_set_exclude (const char * c)
1311{
1312 SL_ENTER(_("sh_suidchk_set_exclude"));
1313
1314 if (c == NULL || c[0] == '\0')
1315 {
1316 SL_RETURN(-1, _("sh_suidchk_set_exclude"));
1317 }
1318
1319 if (0 == sl_strncmp(c, _("NULL"), 4))
1320 {
1321 if (ShSuidchkExclude != NULL)
1322 SH_FREE(ShSuidchkExclude);
1323 ShSuidchkExclude = NULL;
1324 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1325 }
1326
1327 if (ShSuidchkExclude != NULL)
1328 SH_FREE(ShSuidchkExclude);
1329
1330 ShSuidchkExclude = sh_util_strdup (c);
1331 ExcludeLen = sl_strlen (ShSuidchkExclude);
1332 if (ShSuidchkExclude[ExcludeLen-1] == '/')
1333 {
1334 ShSuidchkExclude[ExcludeLen-1] = '\0';
1335 ExcludeLen--;
1336 }
1337 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1338}
1339
1340int sh_suidchk_set_timer (const char * c)
1341{
1342 long val;
1343
1344 SL_ENTER(_("sh_suidchk_set_timer"));
1345
1346 val = strtol (c, (char **)NULL, 10);
1347 if (val <= 0)
1348 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1349 _("suidchk timer"), c);
1350
1351 val = (val <= 0 ? 7200 : val);
1352
1353 ShSuidchkInterval = (time_t) val;
1354 SL_RETURN( 0, _("sh_suidchk_set_timer"));
1355}
1356
1357
1358static void sh_suidchk_free_schedule (void)
1359{
1360 sh_schedule_t * current = ShSuidchkSched;
1361 sh_schedule_t * next = NULL;
1362
1363 while (current != NULL)
1364 {
1365 next = current->next;
1366 SH_FREE(current);
1367 current = next;
1368 }
1369 ShSuidchkSched = NULL;
1370 return;
1371}
1372
1373int sh_suidchk_reconf ()
1374{
1375 sh_suidchk_free_schedule();
1376 set_defaults();
1377 return 0;
1378}
1379
1380int sh_suidchk_set_schedule (const char * str)
1381{
1382 int status;
1383 sh_schedule_t * newSched = NULL;
1384
1385 SL_ENTER(_("sh_suidchk_set_schedule"));
1386
1387 /*
1388 if (ShSuidchkSched != NULL)
1389 {
1390 SH_FREE(ShSuidchkSched);
1391 ShSuidchkSched = NULL;
1392 }
1393 */
1394
1395 if (0 == sl_strncmp(str, _("NULL"), 4))
1396 {
1397 (void) sh_suidchk_free_schedule ();
1398 return 0;
1399 }
1400
1401 newSched = SH_ALLOC(sizeof(sh_schedule_t));
1402 status = create_sched(str, newSched);
1403 if (status != 0)
1404 {
1405 SH_FREE(newSched);
1406 newSched = NULL;
1407 }
1408 else
1409 {
1410 newSched->next = ShSuidchkSched;
1411 ShSuidchkSched = newSched;
1412 }
1413 SL_RETURN( status, _("sh_suidchk_set_schedule"));
1414}
1415
1416
1417
1418int sh_suidchk_set_fps (const char * c)
1419{
1420 long val;
1421
1422 SL_ENTER(_("sh_suidchk_set_fps"));
1423
1424 val = strtol (c, (char **)NULL, 10);
1425 if (val < 0)
1426 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1427 _("suidchk fps"), c);
1428
1429 val = (val < 0 ? 0 : val);
1430
1431 ShSuidchkFps = val;
1432 SL_RETURN( 0, _("sh_suidchk_set_fps"));
1433}
1434
1435int sh_suidchk_set_yield (const char * c)
1436{
1437 int i;
1438 SL_ENTER(_("sh_suidchk_set_yield"));
1439#ifdef HAVE_SCHED_YIELD
1440 i = sh_util_flagval(c, &ShSuidchkYield);
1441#else
1442 (void) c; /* cast to void to avoid compiler warning */
1443 i = -1;
1444#endif
1445 SL_RETURN(i, _("sh_suidchk_set_yield"));
1446}
1447
1448int sh_suidchk_set_activate (const char * c)
1449{
1450 int i;
1451 SL_ENTER(_("sh_suidchk_set_activate"));
1452 i = sh_util_flagval(c, &ShSuidchkActive);
1453 SL_RETURN(i, _("sh_suidchk_set_activate"));
1454}
1455
1456int sh_suidchk_set_nosuid (const char * c)
1457{
1458 int i;
1459 SL_ENTER(_("sh_suidchk_set_nosuid"));
1460 i = sh_util_flagval(c, &ShSuidchkNosuid);
1461 SL_RETURN(i, _("sh_suidchk_set_nosuid"));
1462}
1463
1464int sh_suidchk_set_quarantine (const char * c)
1465{
1466 int i;
1467 SL_ENTER(_("sh_suidchk_set_quarantine"));
1468 i = sh_util_flagval(c, &ShSuidchkQEnable);
1469 SL_RETURN(i, _("sh_suidchk_set_quarantine"));
1470}
1471
1472int sh_suidchk_set_qdelete (const char * c)
1473{
1474 int i;
1475 SL_ENTER(_("sh_suidchk_set_qdelete"));
1476 i = sh_util_flagval(c, &ShSuidchkQDelete);
1477 SL_RETURN(i, _("sh_suidchk_set_qdelete"));
1478}
1479
1480int sh_suidchk_set_qmethod (const char * c)
1481{
1482 long val;
1483 int ret = 0;
1484 struct stat buf;
1485
1486 SL_ENTER(_("sh_suidchk_set_qmethod"));
1487
1488 val = strtol (c, (char **)NULL, 10);
1489 if (val < 0)
1490 {
1491 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1492 _("suidchk qmethod"), c);
1493 ret = -1;
1494 }
1495 else
1496 {
1497 switch (val)
1498 {
1499 case SH_Q_DELETE:
1500 ShSuidchkQMethod = SH_Q_DELETE;
1501 break;
1502 case SH_Q_CHANGEPERM:
1503 ShSuidchkQMethod = SH_Q_CHANGEPERM;
1504 break;
1505 case SH_Q_MOVE:
1506 if (retry_stat (FIL__, __LINE__, DEFAULT_QDIR, &buf) != 0)
1507 {
1508 if (mkdir (DEFAULT_QDIR, 0750) == -1)
1509 {
1510 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
1511 MSG_SUID_ERROR,
1512 _("Unable to create quarantine directory"));
1513 }
1514 }
1515 ShSuidchkQMethod = SH_Q_MOVE;
1516 break;
1517 default:
1518 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1519 _("suidchk qmethod"), c);
1520 ShSuidchkQMethod = -1;
1521 ret = -1;
1522 break;
1523 }
1524 }
1525
1526 SL_RETURN( ret, _("sh_suidchk_set_qmethod"));
1527}
1528
1529#if defined(FSTYPE_STATFS) || defined(FSTYPE_AIX_STATFS)
1530/* dirname.c -- return all but the last element in a path
1531 Copyright (C) 1990 Free Software Foundation, Inc.
1532
1533 This program is free software; you can redistribute it and/or modify
1534 it under the terms of the GNU General Public License as published by
1535 the Free Software Foundation; either version 2, or (at your option)
1536 any later version.
1537
1538 This program is distributed in the hope that it will be useful,
1539 but WITHOUT ANY WARRANTY; without even the implied warranty of
1540 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1541 GNU General Public License for more details.
1542
1543 You should have received a copy of the GNU General Public License
1544 along with this program; if not, write to the Free Software Foundation,
1545 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
1546
1547/* Return the leading directories part of PATH,
1548 allocated with malloc. If out of memory, return 0.
1549 Assumes that trailing slashes have already been
1550 removed. */
1551
1552char * sh_dirname (const char * path)
1553{
1554 char *newpath;
1555 char *slash;
1556 int length; /* Length of result, not including NUL. */
1557
1558 slash = strrchr (path, '/');
1559 if (slash == NULL)
1560 {
1561 /* File is in the current directory. */
1562 path = ".";
1563 length = 1;
1564 }
1565 else
1566 {
1567 /* Remove any trailing slashes from the result. */
1568 while (slash > path && *slash == '/')
1569 --slash;
1570
1571 length = slash - path + 1;
1572 }
1573 newpath = (char *) SH_ALLOC (length + 1);
1574 if (newpath == NULL)
1575 return NULL;
1576 strncpy (newpath, path, length);
1577 newpath[length] = '\0';
1578 return newpath;
1579}
1580/* #ifdef FSTYPE_STATFS */
1581#endif
1582
1583/* fstype.c -- determine type of filesystems that files are on
1584 Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
1585
1586 This program is free software; you can redistribute it and/or modify
1587 it under the terms of the GNU General Public License as published by
1588 the Free Software Foundation; either version 2, or (at your option)
1589 any later version.
1590
1591 This program is distributed in the hope that it will be useful,
1592 but WITHOUT ANY WARRANTY; without even the implied warranty of
1593 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1594 GNU General Public License for more details.
1595
1596 You should have received a copy of the GNU General Public License
1597 along with this program; if not, write to the Free Software
1598 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
1599
1600/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
1601
1602/* Modified by R. Wichmann:
1603 - replaced error() by sh_error_handle()
1604 - replaced xstrdup() by sl_strdup()
1605 - replaced strstr() by sl_strstr()
1606 - some additions to recognize nosuid fs
1607*/
1608
1609/* modetype.h -- file type bits definitions for POSIX systems
1610 Requires sys/types.h sys/stat.h.
1611 Copyright (C) 1990 Free Software Foundation, Inc.
1612
1613 This program is free software; you can redistribute it and/or modify
1614 it under the terms of the GNU General Public License as published by
1615 the Free Software Foundation; either version 2, or (at your option)
1616 any later version.
1617
1618 This program is distributed in the hope that it will be useful,
1619 but WITHOUT ANY WARRANTY; without even the implied warranty of
1620 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1621 GNU General Public License for more details.
1622
1623 You should have received a copy of the GNU General Public License
1624 along with this program; if not, write to the Free Software
1625 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
1626
1627/* POSIX.1 doesn't mention the S_IFMT bits; instead, it uses S_IStype
1628 test macros. To make storing file types more convenient, define
1629 them; the values don't need to correspond to what the kernel uses,
1630 because of the way we use them. */
1631#ifndef S_IFMT /* Doesn't have traditional Unix macros. */
1632#define S_IFBLK 1
1633#define S_IFCHR 2
1634#define S_IFDIR 4
1635#define S_IFREG 8
1636#ifdef S_ISLNK
1637#define S_IFLNK 16
1638#endif
1639#ifdef S_ISFIFO
1640#define S_IFIFO 32
1641#endif
1642#ifdef S_ISSOCK
1643#define S_IFSOCK 64
1644#endif
1645#endif /* !S_IFMT */
1646
1647#ifdef STAT_MACROS_BROKEN
1648#undef S_ISBLK
1649#undef S_ISCHR
1650#undef S_ISDIR
1651#undef S_ISREG
1652#undef S_ISFIFO
1653#undef S_ISLNK
1654#undef S_ISSOCK
1655#undef S_ISMPB
1656#undef S_ISMPC
1657#undef S_ISNWK
1658#endif
1659
1660/* Do the reverse: define the POSIX.1 macros for traditional Unix systems
1661 that don't have them. */
1662#if !defined(S_ISBLK) && defined(S_IFBLK)
1663#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
1664#endif
1665#if !defined(S_ISCHR) && defined(S_IFCHR)
1666#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
1667#endif
1668#if !defined(S_ISDIR) && defined(S_IFDIR)
1669#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1670#endif
1671#if !defined(S_ISREG) && defined(S_IFREG)
1672#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1673#endif
1674#if !defined(S_ISFIFO) && defined(S_IFIFO)
1675#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
1676#endif
1677#if !defined(S_ISLNK) && defined(S_IFLNK)
1678#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1679#endif
1680#if !defined(S_ISSOCK) && defined(S_IFSOCK)
1681#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
1682#endif
1683#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
1684#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
1685#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
1686#endif
1687#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
1688#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
1689#endif
1690
1691
1692static char *filesystem_type_uncached (char *path, char *relpath,
1693 struct stat *statp);
1694
1695#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
1696static int xatoi (const char *cp);
1697#endif
1698
1699#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
1700#include <mntent.h>
1701#if !defined(MOUNTED)
1702# if defined(MNT_MNTTAB) /* HP-UX. */
1703# define MOUNTED MNT_MNTTAB
1704# endif
1705# if defined(MNTTABNAME) /* Dynix. */
1706# define MOUNTED MNTTABNAME
1707# endif
1708#endif
1709#endif
1710
1711#ifdef FSTYPE_GETMNT /* Ultrix. */
1712#include <sys/param.h>
1713#include <sys/mount.h>
1714#include <sys/fs_types.h>
1715#endif
1716
1717#ifdef FSTYPE_USG_STATFS /* SVR3. */
1718#include <sys/statfs.h>
1719#include <sys/fstyp.h>
1720#endif
1721
1722#ifdef FSTYPE_STATVFS /* SVR4. */
1723#include <sys/statvfs.h>
1724#include <sys/fstyp.h>
1725#endif
1726
1727#ifdef FSTYPE_STATFS /* 4.4BSD. */
1728#include <sys/param.h> /* NetBSD needs this. */
1729#include <sys/mount.h>
1730
1731#ifndef MFSNAMELEN /* NetBSD defines this. */
1732static char *
1733fstype_to_string (t)
1734 short t;
1735{
1736#ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
1737 static char *mn[] = INITMOUNTNAMES;
1738 if (t >= 0 && t <= MOUNT_MAXTYPE)
1739 return mn[t];
1740 else
1741 return "?";
1742#else /* !INITMOUNTNAMES */
1743 switch (t)
1744 {
1745#ifdef MOUNT_UFS
1746 case MOUNT_UFS:
1747 return _("ufs");
1748#endif
1749#ifdef MOUNT_ISO9660
1750 case MOUNT_ISO9660:
1751 return _("iso9660fs");
1752#endif
1753#ifdef MOUNT_CD9660
1754 case MOUNT_CD9660:
1755 return _("cd9660");
1756#endif
1757#ifdef MOUNT_NFS
1758 case MOUNT_NFS:
1759 return _("nfs");
1760#endif
1761#ifdef MOUNT_PC
1762 case MOUNT_PC:
1763 return _("pc");
1764#endif
1765#ifdef MOUNT_MFS
1766 case MOUNT_MFS:
1767 return _("mfs");
1768#endif
1769#ifdef MOUNT_LO
1770 case MOUNT_LO:
1771 return _("lofs");
1772#endif
1773#ifdef MOUNT_TFS
1774 case MOUNT_TFS:
1775 return _("tfs");
1776#endif
1777#ifdef MOUNT_TMP
1778 case MOUNT_TMP:
1779 return _("tmp");
1780#endif
1781#ifdef MOUNT_MSDOS
1782 case MOUNT_MSDOS:
1783 return _("msdos");
1784#endif
1785#ifdef MOUNT_LFS
1786 case MOUNT_LFS:
1787 return _("lfs");
1788#endif
1789#ifdef MOUNT_LOFS
1790 case MOUNT_LOFS:
1791 return _("lofs");
1792#endif
1793#ifdef MOUNT_FDESC
1794 case MOUNT_FDESC:
1795 return _("fdesc");
1796#endif
1797#ifdef MOUNT_PORTAL
1798 case MOUNT_PORTAL:
1799 return _("portal");
1800#endif
1801#ifdef MOUNT_NULL
1802 case MOUNT_NULL:
1803 return _("null");
1804#endif
1805#ifdef MOUNT_UMAP
1806 case MOUNT_UMAP:
1807 return _("umap");
1808#endif
1809#ifdef MOUNT_KERNFS
1810 case MOUNT_KERNFS:
1811 return _("kernfs");
1812#endif
1813#ifdef MOUNT_PROCFS
1814 case MOUNT_PROCFS:
1815 return _("procfs");
1816#endif
1817#ifdef MOUNT_DEVFS
1818 case MOUNT_DEVFS:
1819 return _("devfs");
1820#endif
1821#ifdef MOUNT_EXT2FS
1822 case MOUNT_EXT2FS:
1823 return _("ext2fs");
1824#endif
1825#ifdef MOUNT_UNION
1826 case MOUNT_UNION:
1827 return _("union");
1828#endif
1829 default:
1830 return "?";
1831 }
1832#endif /* !INITMOUNTNAMES */
1833}
1834#endif /* !MFSNAMELEN */
1835#endif /* FSTYPE_STATFS */
1836
1837#ifdef FSTYPE_AIX_STATFS /* AIX. */
1838#include <sys/vmount.h>
1839#include <sys/statfs.h>
1840
1841#define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
1842#define f_type f_vfstype
1843
1844static char *
1845fstype_to_string (t)
1846 short t;
1847{
1848 switch (t)
1849 {
1850 case MNT_AIX:
1851 return _("aix"); /* AIX 4.3: NFS filesystems are actually MNT_AIX. */
1852#ifdef MNT_NAMEFS
1853 case MNT_NAMEFS:
1854 return _("namefs");
1855#endif
1856 case MNT_NFS:
1857 return _("nfs");
1858 case MNT_JFS:
1859 return _("jfs");
1860 case MNT_CDROM:
1861 return _("cdrom");
1862#ifdef MNT_PROCFS
1863 case MNT_PROCFS:
1864 return _("procfs");
1865#endif
1866#ifdef MNT_SFS
1867 case MNT_SFS:
1868 return _("sfs");
1869#endif
1870#ifdef MNT_CACHEFS
1871 case MNT_CACHEFS:
1872 return _("cachefs");
1873#endif
1874#ifdef MNT_NFS3
1875 case MNT_NFS3:
1876 return _("nfs3");
1877#endif
1878#ifdef MNT_AUTOFS
1879 case MNT_AUTOFS:
1880 return _("autofs");
1881#endif
1882#ifdef MNT_VXFS
1883 case MNT_VXFS:
1884 return _("vxfs");
1885#endif
1886#ifdef MNT_VXODM
1887 case MNT_VXODM:
1888 return _("veritasfs");
1889#endif
1890#ifdef MNT_UDF
1891 case MNT_UDF:
1892 return _("udfs");
1893#endif
1894#ifdef MNT_NFS4
1895 case MNT_NFS4:
1896 return _("nfs4");
1897#endif
1898#ifdef MNT_RFS4
1899 case MNT_RFS4:
1900 return _("nfs4");
1901#endif
1902#ifdef MNT_CIFS
1903 case MNT_CIFS:
1904 return _("cifs");
1905#endif
1906 default:
1907 return "?";
1908 }
1909}
1910#endif /* FSTYPE_AIX_STATFS */
1911
1912#ifdef AFS
1913#include <netinet/in.h>
1914#include <afs/venus.h>
1915#if __STDC__
1916/* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
1917#undef _VICEIOCTL
1918#define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
1919#endif
1920#ifndef _IOW
1921/* AFS on Solaris 2.3 doesn't get this definition. */
1922#include <sys/ioccom.h>
1923#endif
1924
1925static int
1926in_afs (path)
1927 char *path;
1928{
1929 static char space[2048];
1930 struct ViceIoctl vi;
1931
1932 vi.in_size = 0;
1933 vi.out_size = sizeof (space);
1934 vi.out = space;
1935
1936 if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
1937 && (errno == EINVAL || errno == ENOENT))
1938 return 0;
1939 return 1;
1940}
1941#endif /* AFS */
1942
1943/* Nonzero if the current filesystem's type is known. */
1944static int fstype_known = 0;
1945
1946/* Return a static string naming the type of filesystem that the file PATH,
1947 described by STATP, is on.
1948 RELPATH is the file name relative to the current directory.
1949 Return "unknown" if its filesystem type is unknown. */
1950
1951static char *
1952filesystem_type (char * path, char * relpath, struct stat * statp)
1953{
1954 static char *current_fstype = NULL;
1955 static dev_t current_dev;
1956
1957 if (current_fstype != NULL)
1958 {
1959 if ((0 != fstype_known) && statp->st_dev == current_dev)
1960 return current_fstype; /* Cached value. */
1961 SH_FREE (current_fstype);
1962 }
1963 current_dev = statp->st_dev;
1964 current_fstype = filesystem_type_uncached (path, relpath, statp);
1965 return current_fstype;
1966}
1967
1968/* Return a newly allocated string naming the type of filesystem that the
1969 file PATH, described by STATP, is on.
1970 RELPATH is the file name relative to the current directory.
1971 Return "unknown" if its filesystem type is unknown. */
1972
1973static char *
1974filesystem_type_uncached (path, relpath, statp)
1975 char *path;
1976 char *relpath;
1977 struct stat *statp;
1978{
1979 char * type = NULL;
1980#ifdef MFSNAMELEN /* NetBSD. */
1981 static char my_tmp_type[64];
1982#endif
1983
1984#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
1985 char *table = MOUNTED;
1986 FILE *mfp;
1987 struct mntent *mnt;
1988
1989 if (path == NULL || relpath == NULL)
1990 return NULL;
1991
1992 mfp = setmntent (table, "r");
1993 if (mfp == NULL)
1994 {
1995 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1996 _("setmntent() failed"),
1997 _("filesystem_type_uncached") );
1998 return NULL;
1999 }
2000
2001 /* Find the entry with the same device number as STATP, and return
2002 that entry's fstype. */
2003 while (type == NULL && (mnt = getmntent (mfp)) != NULL)
2004 {
2005 const char *devopt;
2006 dev_t dev;
2007 struct stat disk_stats;
2008
2009#ifdef MNTTYPE_IGNORE
2010 if (0 == strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
2011 continue;
2012#endif
2013
2014 /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
2015 in the options string. For older systems, we need to stat the
2016 directory that the filesystem is mounted on to get it.
2017
2018 Unfortunately, the HPUX 9.x mnttab entries created by automountq
2019 contain a dev= option but the option value does not match the
2020 st_dev value of the file (maybe the lower 16 bits match?). */
2021
2022#if !defined(hpux) && !defined(__hpux__)
2023 devopt = sl_strstr (mnt->mnt_opts, "dev=");
2024 if (devopt)
2025 {
2026 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
2027 dev = (dev_t) xatoi (devopt + 6);
2028 else
2029 dev = (dev_t) xatoi (devopt + 4);
2030 }
2031 else
2032#endif /* not hpux */
2033 {
2034 if (stat (mnt->mnt_dir, &disk_stats) == -1)
2035 {
2036 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
2037 _("stat() failed"),
2038 _("filesystem_type_uncached") );
2039 return NULL;
2040 }
2041 dev = disk_stats.st_dev;
2042 }
2043
2044 if (dev == statp->st_dev)
2045 {
2046 /* check for the "nosuid" option
2047 */
2048#ifdef HAVE_HASMNTOPT
2049 if (NULL == hasmntopt(mnt, "nosuid") || (ShSuidchkNosuid == S_TRUE))
2050 type = mnt->mnt_type;
2051 else
2052 type = _("nosuid"); /* hasmntopt (nosuid) */
2053#else
2054 type = mnt->mnt_type;
2055#endif
2056 }
2057 }
2058
2059 if (endmntent (mfp) == 0)
2060 {
2061 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
2062 _("endmntent() failed"),
2063 _("filesystem_type_uncached") );
2064 }
2065#endif
2066
2067#ifdef FSTYPE_GETMNT /* Ultrix. */
2068 int offset = 0;
2069 struct fs_data fsd;
2070
2071 if (path == NULL || relpath == NULL)
2072 return NULL;
2073
2074 while (type == NULL
2075 && getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 0) > 0)
2076 {
2077 if (fsd.fd_req.dev == statp->st_dev)
2078 type = gt_names[fsd.fd_req.fstype];
2079 }
2080#endif
2081
2082#ifdef FSTYPE_USG_STATFS /* SVR3. */
2083 struct statfs fss;
2084 char typebuf[FSTYPSZ];
2085
2086 if (path == NULL || relpath == NULL)
2087 return NULL;
2088
2089 if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
2090 {
2091 /* Don't die if a file was just removed. */
2092 if (errno != ENOENT)
2093 {
2094 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
2095 _("statfs() failed"),
2096 _("filesystem_type_uncached") );
2097 return NULL;
2098 }
2099 }
2100 else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
2101 type = typebuf;
2102#endif
2103
2104#ifdef FSTYPE_STATVFS /* SVR4. */
2105 struct statvfs fss;
2106
2107 if (path == NULL || relpath == NULL)
2108 return NULL;
2109
2110 if (statvfs (relpath, &fss) == -1)
2111 {
2112 /* Don't die if a file was just removed. */
2113 if (errno != ENOENT)
2114 {
2115 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
2116 _("statvfs() failed"),
2117 _("filesystem_type_uncached") );
2118 return NULL;
2119 }
2120 }
2121 else
2122 {
2123 type = fss.f_basetype;
2124
2125 /* patch by Konstantin Khrooschev <nathoo@co.ru>
2126 */
2127 if( (fss.f_flag & ST_NOSUID) && (ShSuidchkNosuid == S_FALSE))
2128 type = _("nosuid");
2129 }
2130 (void) statp; /* fix compiler warning */
2131#endif
2132
2133#ifdef FSTYPE_STATFS /* 4.4BSD. */
2134 struct statfs fss;
2135 char *p;
2136#if defined(MNT_VISFLAGMASK) && defined(HAVE_STRUCT_STATFS_F_FLAGS)
2137 int flags;
2138#endif
2139 /* char * sh_dirname(const char *path); */
2140
2141 if (path == NULL || relpath == NULL)
2142 return NULL;
2143
2144 if (S_ISLNK (statp->st_mode))
2145 p = sh_dirname (relpath);
2146 else
2147 p = relpath;
2148
2149 if (statfs (p, &fss) == -1)
2150 {
2151 /* Don't die if symlink to nonexisting file, or a file that was
2152 just removed. */
2153 if (errno != ENOENT)
2154 {
2155 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
2156 _("statfs() failed"),
2157 _("filesystem_type_uncached") );
2158 return NULL;
2159 }
2160 }
2161 else
2162 {
2163
2164#ifdef MFSNAMELEN /* NetBSD. */
2165 /* MEMORY LEAK !!!
2166 * type = sh_util_strdup (fss.f_fstypename);
2167 */
2168 sl_strlcpy (my_tmp_type, fss.f_fstypename, 64);
2169 type = my_tmp_type;
2170#else
2171 type = fstype_to_string (fss.f_type);
2172#endif
2173
2174#ifdef HAVE_STRUCT_STATFS_F_FLAGS
2175#ifdef MNT_VISFLAGMASK
2176 flags = fss.f_flags & MNT_VISFLAGMASK;
2177 if ((flags & MNT_NOSUID) && (ShSuidchkNosuid == S_FALSE))
2178#else
2179 if ((fss.f_flags & MNT_NOSUID) && (ShSuidchkNosuid == S_FALSE))
2180#endif
2181 type = _("nosuid");
2182#endif
2183 }
2184 if (p != relpath)
2185 SH_FREE (p);
2186#endif
2187
2188#ifdef AFS
2189 if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
2190 type = "afs";
2191#endif
2192
2193 /* An unknown value can be caused by an ENOENT error condition.
2194 Don't cache those values. */
2195 fstype_known = (int)(type != NULL);
2196
2197 return sh_util_strdup (type ? type : "unknown");
2198}
2199
2200#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
2201/* Return the value of the hexadecimal number represented by CP.
2202 No prefix (like '0x') or suffix (like 'h') is expected to be
2203 part of CP. */
2204
2205static int
2206xatoi (cp)
2207 const char *cp;
2208{
2209 int val;
2210
2211 val = 0;
2212 while (*cp != '\0')
2213 {
2214 /*@+charint@*/
2215 if (*cp >= 'a' && *cp <= 'f')
2216 val = val * 16 + *cp - 'a' + 10;
2217 else if (*cp >= 'A' && *cp <= 'F')
2218 val = val * 16 + *cp - 'A' + 10;
2219 else if (*cp >= '0' && *cp <= '9')
2220 val = val * 16 + *cp - '0';
2221 else
2222 break;
2223 /*@-charint@*/
2224 cp++;
2225 }
2226 return val;
2227}
2228#endif
2229
2230
2231
2232#endif
2233
2234
2235/* #ifdef SH_USE_UTMP */
2236#endif
2237
2238
2239
Note: See TracBrowser for help on using the repository browser.