source: trunk/src/sh_suidchk.c@ 252

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

Add code to check for stale file records on close() and fclose(), fix sl_close() to handle open stream (ticket #163).

File size: 53.6 KB
RevLine 
[1]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>
[94]32
[1]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
[137]71#define NEED_ADD_DIRENT
[1]72
73#include "samhain.h"
[131]74#include "sh_pthread.h"
[1]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 {
[119]116 N_("suidchecknosuid"),
117 sh_suidchk_set_nosuid
118 },
119 {
[1]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;
[119]142static int ShSuidchkNosuid = S_FALSE;
[1]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;
[68]149static size_t ExcludeLen = 0;
[1]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
[149]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
[1]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;
[132]200 char errbuf[SH_ERRBUF_SIZE];
[1]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,
[132]226 sh_error_message(errno, errbuf, sizeof(errbuf)));
[1]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,
[132]245 sh_error_message(errno, errbuf, sizeof(errbuf)));
[1]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,
[132]254 sh_error_message(errno, errbuf, sizeof(errbuf)));
[1]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,
[132]280 sh_error_message(errno, errbuf, sizeof(errbuf)));
[1]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,
[132]288 sh_error_message(errno, errbuf, sizeof(errbuf)));
[1]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,
[132]295 sh_error_message(errno, errbuf, sizeof(errbuf)));
[252]296 (void) sl_close_fd(FIL__, __LINE__, fd);
[1]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"));
[252]305 (void) sl_close_fd(FIL__, __LINE__, fd);
[1]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"));
[252]313 (void) sl_close_fd(FIL__, __LINE__, fd);
[1]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"));
[252]321 (void) sl_close_fd(FIL__, __LINE__, fd);
[1]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,
[132]335 sh_error_message(errno, errbuf, sizeof(errbuf)));
[252]336 (void) sl_close_fd(FIL__, __LINE__, fd);
[1]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"));
[252]343 (void) sl_close_fd(FIL__, __LINE__, fd);
[1]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"));
[252]351 (void) sl_close_fd(FIL__, __LINE__, fd);
[1]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,
[132]360 sh_error_message(errno, errbuf, sizeof(errbuf)));
[252]361 (void) sl_close_fd(FIL__, __LINE__, fd);
[1]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,
[132]371 sh_error_message(errno, errbuf, sizeof(errbuf)));
[252]372 (void) sl_close_fd(FIL__, __LINE__, fd);
[1]373 return -1;
374 }
375 }
[252]376 (void) sl_close_fd (FIL__, __LINE__, fd);
[1]377 return (0);
378 }
379}
380
[94]381static int do_truncate (const char * path_in)
[1]382{
[94]383 int caperr;
384 int result;
385 char * path;
[132]386 char errbuf[SH_ERRBUF_SIZE];
[1]387
388 if (0 != chdir("/"))
389 {
390 sh_error_handle ((-1), FIL__, __LINE__, errno,
391 MSG_SUID_ERROR,
[132]392 sh_error_message(errno, errbuf, sizeof(errbuf)));
[1]393 }
394
395 if (0 != (caperr = sl_get_cap_qdel()))
396 {
397 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
[132]398 sh_error_message (caperr, errbuf, sizeof(errbuf)),
[1]399 _("sl_get_cap_qdel"));
400 }
401
[94]402 path = sh_util_strdup (path_in);
[1]403 result = do_truncate_int (path, 0);
[94]404 SH_FREE(path);
[1]405
406 if (0 != (caperr = sl_drop_cap_qdel()))
407 {
408 sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
[132]409 sh_error_message (caperr, errbuf, sizeof(errbuf)),
[1]410 _("sl_drop_cap_qdel"));
411 }
412
413 if (0 != chdir("/"))
414 {
415 sh_error_handle ((-1), FIL__, __LINE__, errno,
416 MSG_SUID_ERROR,
[132]417 sh_error_message(errno, errbuf, sizeof(errbuf)));
[1]418 }
419 return result;
420}
421
[94]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;
[249]464 int writeFile = -1;
[94]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)
[166]528 writeFile = open (filetmp, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IXUSR);
[94]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
[252]570 (void) sl_close_fd (FIL__, __LINE__, readFile);
[94]571 (void) fchmod(writeFile, S_IRUSR | S_IWUSR | S_IXUSR);
[252]572 (void) sl_close_fd (FIL__, __LINE__, writeFile);
[94]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);
[252]615 (void) sl_fclose (FIL__, __LINE__, filePtr);
[94]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;
[132]645 char errbuf[SH_ERRBUF_SIZE];
[94]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,
[132]670 sh_error_message (caperr, errbuf, sizeof(errbuf)),
[94]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,
[132]783 sh_error_message (caperr, errbuf, sizeof(errbuf)),
[94]784 _("sl_drop_cap_qdel"));
785 }
786
787 if (file_d != -1)
788 {
789 do {
[252]790 status = sl_close_fd (FIL__, __LINE__, file_d);
[94]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@*/
[132]822
[94]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
[1]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;
[115]859 int fflags;
[1]860 char * fs;
[170]861 long sl_status;
[227]862 file_type * theFile = NULL;
[19]863 char fileHash[2*(KEY_LEN + 1)];
[1]864
[170]865 struct sh_dirent * dirlist;
866 struct sh_dirent * dirlist_orig;
[132]867 char errbuf[SH_ERRBUF_SIZE];
[22]868
[1]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,
[132]889 sh_error_message (status, errbuf, sizeof(errbuf)), tmp);
[1]890 SH_FREE(tmp);
891 SL_RETURN( (-1), _("sh_suidchk_check_internal"));
892 }
893
[94]894 /* Loop over directory entries
895 */
[137]896 SH_MUTEX_LOCK(mutex_readdir);
[131]897
[170]898 dirlist = NULL;
899 dirlist_orig = NULL;
900
[1]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
[131]913 dirlist = addto_sh_dirlist (thisEntry, dirlist);
914 }
[1]915
[131]916 } while (thisEntry != NULL);
[94]917
[137]918 SH_MUTEX_UNLOCK(mutex_readdir);
[94]919
[131]920 closedir(thisDir);
[1]921
[131]922 dirlist_orig = dirlist;
[1]923
[170]924 sl_status = SL_ENONE;
925
[131]926 do {
927
928 /* If the directory is empty, dirlist = NULL
929 */
930 if (!dirlist)
931 break;
932
[143]933 if (sig_urgent > 0) {
934 SL_RETURN( (0), _("sh_suidchk_check_internal"));
935 }
936
[131]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);
[227]961 SH_FREE(tmpcat);
[131]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 }
[1]982
[131]983 status = (int) retry_lstat(FIL__, __LINE__, tmpcat, &buf);
[1]984
[131]985 if (status != 0)
986 {
[252]987 int elevel = SH_ERR_ERR;
988 size_t tlen;
989
[131]990 status = errno;
991 tmp = sh_util_safe_name(tmpcat);
[252]992 tlen = strlen(tmp);
993 if (tlen >= 6 && 0 == strcmp(&tmp[tlen-6], _("/.gvfs")))
994 elevel = SH_ERR_NOTICE;
995 sh_error_handle (elevel, FIL__, __LINE__, status, MSG_ERR_LSTAT,
[132]996 sh_error_message(status, errbuf, sizeof(errbuf)),
[252]997 tmp );
[131]998 SH_FREE(tmp);
999 }
1000 else
1001 {
1002 if (/*@-usedef@*/S_ISDIR(buf.st_mode)/*@+usedef@*/ &&
1003 (ShSuidchkExclude == NULL ||
1004 0 != strcmp(tmpcat, ShSuidchkExclude)))
1005 {
1006 /* fs is a STATIC string or NULL
1007 */
1008 fs = filesystem_type (tmpcat, tmpcat, &buf);
1009 if (fs != NULL
[30]1010#ifndef SH_SUIDTESTDIR
[131]1011 &&
1012 0 != strncmp (_("afs"), fs, 3) &&
1013 0 != strncmp (_("devfs"), fs, 5) &&
[231]1014 0 != strncmp (_("fdesc"), fs, 5) &&
[131]1015 0 != strncmp (_("iso9660"), fs, 7) &&
[231]1016 0 != strncmp (_("cd9660"), fs, 6) &&
[131]1017 0 != strncmp (_("lustre"), fs, 6) &&
1018 0 != strncmp (_("mmfs"), fs, 4) &&
1019 0 != strncmp (_("msdos"), fs, 5) &&
1020 0 != strncmp (_("nfs"), fs, 3) &&
1021 0 != strncmp (_("proc"), fs, 4) &&
[231]1022 0 != strncmp (_("sysfs"), fs, 5) &&
[131]1023 0 != strncmp (_("vfat"), fs, 4)
[30]1024#endif
[131]1025 )
1026 {
1027 if ((ShSuidchkNosuid == S_TRUE) ||
1028 (0 != strncmp (_("nosuid"), fs, 6)))
1029 /* fprintf(stderr, "%s: %s\n", fs, tmpcat); */
1030 (void) sh_suidchk_check_internal(tmpcat);
1031 }
1032 }
1033 else if (S_ISREG(buf.st_mode) &&
1034 (0 !=(S_ISUID & buf.st_mode) ||
[1]1035#if defined(HOST_IS_LINUX)
[131]1036 (0 !=(S_ISGID & buf.st_mode) &&
1037 0 !=(S_IXGRP & buf.st_mode))
[1]1038#else
[131]1039 0 !=(S_ISGID & buf.st_mode)
[1]1040#endif
[131]1041 )
1042 )
1043 {
[227]1044 theFile = SH_ALLOC(sizeof(file_type));
1045
1046 (void) sl_strlcpy (theFile->fullpath, tmpcat, PATH_MAX);
1047 theFile->check_mask = sh_files_maskof(SH_LEVEL_READONLY);
1048 CLEAR_SH_FFLAG_REPORTED(theFile->file_reported);
1049 theFile->attr_string = NULL;
1050 theFile->link_path = NULL;
[131]1051
1052 status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO],
[138]1053 dirlist->sh_d_name,
[227]1054 theFile, fileHash, 0);
[131]1055
1056 tmp = sh_util_safe_name(tmpcat);
1057
1058 if (status != 0)
1059 {
1060 sh_error_handle (ShSuidchkSeverity, FIL__, __LINE__,
1061 0, MSG_E_SUBGPATH,
1062 _("Could not check suid/sgid file"),
1063 _("sh_suidchk_check_internal"),
1064 tmp);
1065 }
1066 else
1067 {
1068
1069 if ( sh.flag.update == S_TRUE &&
1070 (sh.flag.checkSum == SH_CHECK_INIT ||
1071 sh.flag.checkSum == SH_CHECK_CHECK))
1072 {
1073 /* Updating database. Report new files that
1074 * are not in database already. Then compare
1075 * to database and report changes.
1076 */
1077 if (-1 == sh_hash_have_it (tmpcat))
1078 {
1079 sh_error_handle ((-1), FIL__, __LINE__,
1080 0, MSG_SUID_FOUND, tmp );
1081 }
1082 else
1083 {
1084 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
1085 0, MSG_SUID_FOUND, tmp );
1086 }
1087
1088 if (0 == sh_hash_compdata (SH_LEVEL_READONLY,
[227]1089 theFile, fileHash,
[131]1090 _("[SuidCheck]"),
1091 ShSuidchkSeverity))
1092 {
[227]1093 sh_hash_pushdata_memory (theFile, fileHash);
[131]1094 }
1095
1096 sh_hash_addflag(tmpcat, SH_FFLAG_SUIDCHK);
1097
1098 }
1099
1100 else if (sh.flag.checkSum == SH_CHECK_INIT &&
1101 sh.flag.update == S_FALSE )
1102 {
1103 /* Running init. Report on files detected.
1104 */
[227]1105 sh_hash_pushdata (theFile, fileHash);
[131]1106 sh_error_handle ((-1), FIL__, __LINE__,
1107 0, MSG_SUID_FOUND, tmp );
1108 }
1109
1110 else if (sh.flag.checkSum == SH_CHECK_CHECK )
1111 {
1112 /* Running file check. Report on new files
1113 * detected, and quarantine them.
1114 */
1115 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
1116 0, MSG_SUID_FOUND, tmp );
1117
1118 fflags = sh_hash_getflags(tmpcat);
1119
1120 if ( (-1 == fflags) || (!SH_FFLAG_SUIDCHK_SET(fflags)))
1121 {
1122 if (-1 == fflags)
[132]1123 {
[227]1124 (void) sh_unix_gmttime (theFile->ctime, timestrc, sizeof(timestrc));
1125 (void) sh_unix_gmttime (theFile->atime, timestra, sizeof(timestra));
1126 (void) sh_unix_gmttime (theFile->mtime, timestrm, sizeof(timestrm));
[132]1127
[227]1128 report_file(tmpcat, theFile, timestrc, timestra, timestrm);
[132]1129 }
[131]1130 /* Quarantine file according to configured method
1131 */
1132 if (ShSuidchkQEnable == S_TRUE)
1133 {
1134 switch (ShSuidchkQMethod)
1135 {
1136 case SH_Q_DELETE:
[227]1137 sh_q_delete(theFile->fullpath);
[131]1138 break;
1139 case SH_Q_CHANGEPERM:
[227]1140 sh_q_changeperm(theFile->fullpath);
[131]1141 break;
1142 case SH_Q_MOVE:
[227]1143 sh_q_move(theFile->fullpath, theFile, timestrc, timestra, timestrm);
[131]1144 break;
1145 default:
1146 sh_error_handle (ShSuidchkSeverity, FIL__,
1147 __LINE__, 0, MSG_SUID_QREPORT,
1148 _("Bad quarantine method"), tmp);
1149 break;
1150 }
1151 }
1152 else
1153 {
1154 /* 1.8.1 push file to in-memory database
1155 */
1156 (void) sh_hash_compdata (SH_LEVEL_READONLY,
[227]1157 theFile, fileHash,
[131]1158 _("[SuidCheck]"),
1159 ShSuidchkSeverity);
1160
1161 sh_hash_addflag(tmpcat, SH_FFLAG_SUIDCHK);
1162
1163 }
1164 }
1165 else
1166 {
1167 /* File exists. Check for modifications.
1168 */
1169 (void) sh_hash_compdata (SH_LEVEL_READONLY,
[227]1170 theFile, fileHash,
[131]1171 _("[SuidCheck]"),
1172 ShSuidchkSeverity);
1173
1174 sh_hash_addflag(tmpcat, SH_FFLAG_SUIDCHK);
1175
1176 }
1177 }
1178 }
1179 SH_FREE(tmp);
[227]1180 if (theFile->attr_string) SH_FREE(theFile->attr_string);
1181 if (theFile->link_path) SH_FREE(theFile->link_path);
1182 SH_FREE(theFile);
[131]1183 }
1184 }
1185 SH_FREE(tmpcat);
[115]1186
[131]1187
[1]1188#ifdef HAVE_SCHED_YIELD
1189 if (ShSuidchkYield == S_TRUE)
1190 {
1191 if (sched_yield() == -1)
1192 {
1193 status = errno;
1194 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
[131]1195 _("Failed to release time slice"),
[1]1196 _("sh_suidchk_check_internal") );
1197 }
1198 }
1199#endif
[131]1200
1201 dirlist = dirlist->next;
[68]1202
[131]1203 } while (dirlist != NULL);
[1]1204
[131]1205
1206 kill_sh_dirlist (dirlist_orig);
1207
[1]1208 SL_RETURN( (0), _("sh_suidchk_check_internal"));
1209}
1210
1211/*************
1212 *
1213 * module init
1214 *
1215 *************/
[140]1216int sh_suidchk_init (struct mod_type * arg)
[1]1217{
[140]1218 (void) arg;
[1]1219 if (ShSuidchkActive == S_FALSE)
1220 return (-1);
1221
1222 return (0);
1223}
1224
1225
1226/*************
1227 *
1228 * module cleanup
1229 *
1230 *************/
1231int sh_suidchk_end ()
1232{
1233 return (0);
1234}
1235
1236
1237/*************
1238 *
1239 * module timer
1240 *
1241 *************/
1242int sh_suidchk_timer (time_t tcurrent)
1243{
1244 if (sh.flag.checkSum == SH_CHECK_INIT)
1245 return -1;
1246
1247 /* One-shot (not daemon and not loop forever)
1248 */
1249 if (sh.flag.isdaemon != S_TRUE && sh.flag.loop == S_FALSE)
1250 return -1;
1251
1252 if (ShSuidchkSched != NULL)
1253 {
1254 return test_sched(ShSuidchkSched);
1255 }
1256 if ((time_t) (tcurrent - lastcheck) >= ShSuidchkInterval)
1257 {
1258 lastcheck = tcurrent;
1259 return (-1);
1260 }
1261 return 0;
1262}
1263
1264/*************
1265 *
1266 * module check
1267 *
1268 *************/
1269
1270int sh_suidchk_check ()
1271{
1272 int status;
1273
1274 SL_ENTER(_("sh_suidchk_check"));
1275
1276 sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
1277 _("Checking for SUID programs"),
1278 _("suidchk_check") );
1279
1280 FileLimNow = time(NULL);
1281 FileLimStart = FileLimNow;
1282 FileLimNum = 0;
1283 FileLimTotal = 0;
1284
[22]1285#ifdef SH_SUIDTESTDIR
1286 status = sh_suidchk_check_internal (SH_SUIDTESTDIR);
1287#else
[1]1288 status = sh_suidchk_check_internal ("/");
[22]1289#endif
[1]1290
1291 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_SUID_SUMMARY,
1292 FileLimTotal,
1293 (long) (time(NULL) - FileLimStart) );
1294
1295 SL_RETURN(status, _("sh_suidchk_check"));
1296}
1297
1298/*************
1299 *
1300 * module setup
1301 *
1302 *************/
1303
[68]1304int sh_suidchk_set_severity (const char * c)
[1]1305{
1306 int retval;
1307 char tmp[32];
1308
1309 SL_ENTER(_("sh_suidchk_set_severity"));
1310 tmp[0] = '='; tmp[1] = '\0';
1311 (void) sl_strlcat (tmp, c, 32);
1312 retval = sh_error_set_level (tmp, &ShSuidchkSeverity);
1313 SL_RETURN(retval, _("sh_suidchk_set_severity"));
1314}
1315
[68]1316int sh_suidchk_set_exclude (const char * c)
[1]1317{
1318 SL_ENTER(_("sh_suidchk_set_exclude"));
[68]1319
[1]1320 if (c == NULL || c[0] == '\0')
1321 {
1322 SL_RETURN(-1, _("sh_suidchk_set_exclude"));
1323 }
1324
1325 if (0 == sl_strncmp(c, _("NULL"), 4))
1326 {
1327 if (ShSuidchkExclude != NULL)
1328 SH_FREE(ShSuidchkExclude);
1329 ShSuidchkExclude = NULL;
1330 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1331 }
1332
1333 if (ShSuidchkExclude != NULL)
1334 SH_FREE(ShSuidchkExclude);
1335
[68]1336 ShSuidchkExclude = sh_util_strdup (c);
1337 ExcludeLen = sl_strlen (ShSuidchkExclude);
1338 if (ShSuidchkExclude[ExcludeLen-1] == '/')
[1]1339 {
[68]1340 ShSuidchkExclude[ExcludeLen-1] = '\0';
[55]1341 ExcludeLen--;
[1]1342 }
1343 SL_RETURN(0, _("sh_suidchk_set_exclude"));
1344}
1345
[68]1346int sh_suidchk_set_timer (const char * c)
[1]1347{
1348 long val;
1349
1350 SL_ENTER(_("sh_suidchk_set_timer"));
1351
1352 val = strtol (c, (char **)NULL, 10);
1353 if (val <= 0)
1354 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1355 _("suidchk timer"), c);
1356
1357 val = (val <= 0 ? 7200 : val);
1358
1359 ShSuidchkInterval = (time_t) val;
1360 SL_RETURN( 0, _("sh_suidchk_set_timer"));
1361}
1362
1363
[170]1364static void sh_suidchk_free_schedule (void)
[1]1365{
1366 sh_schedule_t * current = ShSuidchkSched;
1367 sh_schedule_t * next = NULL;
1368
1369 while (current != NULL)
1370 {
1371 next = current->next;
1372 SH_FREE(current);
1373 current = next;
1374 }
1375 ShSuidchkSched = NULL;
[149]1376 return;
[1]1377}
1378
[149]1379int sh_suidchk_reconf ()
1380{
1381 sh_suidchk_free_schedule();
1382 set_defaults();
[150]1383 return 0;
[149]1384}
1385
[68]1386int sh_suidchk_set_schedule (const char * str)
[1]1387{
1388 int status;
1389 sh_schedule_t * newSched = NULL;
1390
1391 SL_ENTER(_("sh_suidchk_set_schedule"));
1392
1393 /*
1394 if (ShSuidchkSched != NULL)
1395 {
1396 SH_FREE(ShSuidchkSched);
1397 ShSuidchkSched = NULL;
1398 }
1399 */
1400
1401 if (0 == sl_strncmp(str, _("NULL"), 4))
1402 {
1403 (void) sh_suidchk_free_schedule ();
1404 return 0;
1405 }
1406
1407 newSched = SH_ALLOC(sizeof(sh_schedule_t));
1408 status = create_sched(str, newSched);
1409 if (status != 0)
1410 {
1411 SH_FREE(newSched);
1412 newSched = NULL;
1413 }
1414 else
1415 {
1416 newSched->next = ShSuidchkSched;
1417 ShSuidchkSched = newSched;
1418 }
1419 SL_RETURN( status, _("sh_suidchk_set_schedule"));
1420}
1421
1422
1423
[68]1424int sh_suidchk_set_fps (const char * c)
[1]1425{
1426 long val;
1427
1428 SL_ENTER(_("sh_suidchk_set_fps"));
1429
1430 val = strtol (c, (char **)NULL, 10);
1431 if (val < 0)
1432 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1433 _("suidchk fps"), c);
1434
1435 val = (val < 0 ? 0 : val);
1436
1437 ShSuidchkFps = val;
1438 SL_RETURN( 0, _("sh_suidchk_set_fps"));
1439}
1440
[68]1441int sh_suidchk_set_yield (const char * c)
[1]1442{
1443 int i;
1444 SL_ENTER(_("sh_suidchk_set_yield"));
1445#ifdef HAVE_SCHED_YIELD
1446 i = sh_util_flagval(c, &ShSuidchkYield);
1447#else
1448 (void) c; /* cast to void to avoid compiler warning */
1449 i = -1;
1450#endif
1451 SL_RETURN(i, _("sh_suidchk_set_yield"));
1452}
1453
[68]1454int sh_suidchk_set_activate (const char * c)
[1]1455{
1456 int i;
1457 SL_ENTER(_("sh_suidchk_set_activate"));
1458 i = sh_util_flagval(c, &ShSuidchkActive);
1459 SL_RETURN(i, _("sh_suidchk_set_activate"));
1460}
1461
[119]1462int sh_suidchk_set_nosuid (const char * c)
1463{
1464 int i;
1465 SL_ENTER(_("sh_suidchk_set_nosuid"));
1466 i = sh_util_flagval(c, &ShSuidchkNosuid);
1467 SL_RETURN(i, _("sh_suidchk_set_nosuid"));
1468}
1469
[68]1470int sh_suidchk_set_quarantine (const char * c)
[1]1471{
1472 int i;
1473 SL_ENTER(_("sh_suidchk_set_quarantine"));
1474 i = sh_util_flagval(c, &ShSuidchkQEnable);
1475 SL_RETURN(i, _("sh_suidchk_set_quarantine"));
1476}
1477
[68]1478int sh_suidchk_set_qdelete (const char * c)
[1]1479{
1480 int i;
1481 SL_ENTER(_("sh_suidchk_set_qdelete"));
1482 i = sh_util_flagval(c, &ShSuidchkQDelete);
1483 SL_RETURN(i, _("sh_suidchk_set_qdelete"));
1484}
1485
[68]1486int sh_suidchk_set_qmethod (const char * c)
[1]1487{
1488 long val;
1489 int ret = 0;
[22]1490 struct stat buf;
[1]1491
1492 SL_ENTER(_("sh_suidchk_set_qmethod"));
1493
1494 val = strtol (c, (char **)NULL, 10);
1495 if (val < 0)
1496 {
1497 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1498 _("suidchk qmethod"), c);
1499 ret = -1;
1500 }
1501 else
1502 {
1503 switch (val)
1504 {
1505 case SH_Q_DELETE:
1506 ShSuidchkQMethod = SH_Q_DELETE;
1507 break;
1508 case SH_Q_CHANGEPERM:
1509 ShSuidchkQMethod = SH_Q_CHANGEPERM;
1510 break;
1511 case SH_Q_MOVE:
[22]1512 if (retry_stat (FIL__, __LINE__, DEFAULT_QDIR, &buf) != 0)
[1]1513 {
1514 if (mkdir (DEFAULT_QDIR, 0750) == -1)
1515 {
1516 sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
1517 MSG_SUID_ERROR,
1518 _("Unable to create quarantine directory"));
1519 }
1520 }
1521 ShSuidchkQMethod = SH_Q_MOVE;
1522 break;
1523 default:
1524 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1525 _("suidchk qmethod"), c);
1526 ShSuidchkQMethod = -1;
1527 ret = -1;
1528 break;
1529 }
1530 }
1531
1532 SL_RETURN( ret, _("sh_suidchk_set_qmethod"));
1533}
1534
1535#if defined(FSTYPE_STATFS) || defined(FSTYPE_AIX_STATFS)
1536/* dirname.c -- return all but the last element in a path
1537 Copyright (C) 1990 Free Software Foundation, Inc.
1538
1539 This program is free software; you can redistribute it and/or modify
1540 it under the terms of the GNU General Public License as published by
1541 the Free Software Foundation; either version 2, or (at your option)
1542 any later version.
1543
1544 This program is distributed in the hope that it will be useful,
1545 but WITHOUT ANY WARRANTY; without even the implied warranty of
1546 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1547 GNU General Public License for more details.
1548
1549 You should have received a copy of the GNU General Public License
1550 along with this program; if not, write to the Free Software Foundation,
1551 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
1552
1553/* Return the leading directories part of PATH,
1554 allocated with malloc. If out of memory, return 0.
1555 Assumes that trailing slashes have already been
1556 removed. */
1557
1558char * sh_dirname (const char * path)
1559{
1560 char *newpath;
1561 char *slash;
1562 int length; /* Length of result, not including NUL. */
1563
1564 slash = strrchr (path, '/');
1565 if (slash == NULL)
1566 {
1567 /* File is in the current directory. */
1568 path = ".";
1569 length = 1;
1570 }
1571 else
1572 {
1573 /* Remove any trailing slashes from the result. */
1574 while (slash > path && *slash == '/')
1575 --slash;
1576
1577 length = slash - path + 1;
1578 }
1579 newpath = (char *) SH_ALLOC (length + 1);
1580 if (newpath == NULL)
1581 return NULL;
1582 strncpy (newpath, path, length);
1583 newpath[length] = '\0';
1584 return newpath;
1585}
1586/* #ifdef FSTYPE_STATFS */
1587#endif
1588
1589/* fstype.c -- determine type of filesystems that files are on
1590 Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
1591
1592 This program is free software; you can redistribute it and/or modify
1593 it under the terms of the GNU General Public License as published by
1594 the Free Software Foundation; either version 2, or (at your option)
1595 any later version.
1596
1597 This program is distributed in the hope that it will be useful,
1598 but WITHOUT ANY WARRANTY; without even the implied warranty of
1599 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1600 GNU General Public License for more details.
1601
1602 You should have received a copy of the GNU General Public License
1603 along with this program; if not, write to the Free Software
1604 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
1605
1606/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
1607
1608/* Modified by R. Wichmann:
1609 - replaced error() by sh_error_handle()
1610 - replaced xstrdup() by sl_strdup()
1611 - replaced strstr() by sl_strstr()
1612 - some additions to recognize nosuid fs
1613*/
1614
1615/* modetype.h -- file type bits definitions for POSIX systems
1616 Requires sys/types.h sys/stat.h.
1617 Copyright (C) 1990 Free Software Foundation, Inc.
1618
1619 This program is free software; you can redistribute it and/or modify
1620 it under the terms of the GNU General Public License as published by
1621 the Free Software Foundation; either version 2, or (at your option)
1622 any later version.
1623
1624 This program is distributed in the hope that it will be useful,
1625 but WITHOUT ANY WARRANTY; without even the implied warranty of
1626 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1627 GNU General Public License for more details.
1628
1629 You should have received a copy of the GNU General Public License
1630 along with this program; if not, write to the Free Software
1631 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
1632
1633/* POSIX.1 doesn't mention the S_IFMT bits; instead, it uses S_IStype
1634 test macros. To make storing file types more convenient, define
1635 them; the values don't need to correspond to what the kernel uses,
1636 because of the way we use them. */
1637#ifndef S_IFMT /* Doesn't have traditional Unix macros. */
1638#define S_IFBLK 1
1639#define S_IFCHR 2
1640#define S_IFDIR 4
1641#define S_IFREG 8
1642#ifdef S_ISLNK
1643#define S_IFLNK 16
1644#endif
1645#ifdef S_ISFIFO
1646#define S_IFIFO 32
1647#endif
1648#ifdef S_ISSOCK
1649#define S_IFSOCK 64
1650#endif
1651#endif /* !S_IFMT */
1652
1653#ifdef STAT_MACROS_BROKEN
1654#undef S_ISBLK
1655#undef S_ISCHR
1656#undef S_ISDIR
1657#undef S_ISREG
1658#undef S_ISFIFO
1659#undef S_ISLNK
1660#undef S_ISSOCK
1661#undef S_ISMPB
1662#undef S_ISMPC
1663#undef S_ISNWK
1664#endif
1665
1666/* Do the reverse: define the POSIX.1 macros for traditional Unix systems
1667 that don't have them. */
1668#if !defined(S_ISBLK) && defined(S_IFBLK)
1669#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
1670#endif
1671#if !defined(S_ISCHR) && defined(S_IFCHR)
1672#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
1673#endif
1674#if !defined(S_ISDIR) && defined(S_IFDIR)
1675#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1676#endif
1677#if !defined(S_ISREG) && defined(S_IFREG)
1678#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1679#endif
1680#if !defined(S_ISFIFO) && defined(S_IFIFO)
1681#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
1682#endif
1683#if !defined(S_ISLNK) && defined(S_IFLNK)
1684#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1685#endif
1686#if !defined(S_ISSOCK) && defined(S_IFSOCK)
1687#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
1688#endif
1689#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
1690#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
1691#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
1692#endif
1693#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
1694#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
1695#endif
1696
1697
1698static char *filesystem_type_uncached (char *path, char *relpath,
1699 struct stat *statp);
1700
1701#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
[199]1702static int xatoi (const char *cp);
[1]1703#endif
1704
1705#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
1706#include <mntent.h>
1707#if !defined(MOUNTED)
1708# if defined(MNT_MNTTAB) /* HP-UX. */
1709# define MOUNTED MNT_MNTTAB
1710# endif
1711# if defined(MNTTABNAME) /* Dynix. */
1712# define MOUNTED MNTTABNAME
1713# endif
1714#endif
1715#endif
1716
1717#ifdef FSTYPE_GETMNT /* Ultrix. */
1718#include <sys/param.h>
1719#include <sys/mount.h>
1720#include <sys/fs_types.h>
1721#endif
1722
1723#ifdef FSTYPE_USG_STATFS /* SVR3. */
1724#include <sys/statfs.h>
1725#include <sys/fstyp.h>
1726#endif
1727
1728#ifdef FSTYPE_STATVFS /* SVR4. */
1729#include <sys/statvfs.h>
1730#include <sys/fstyp.h>
1731#endif
1732
1733#ifdef FSTYPE_STATFS /* 4.4BSD. */
1734#include <sys/param.h> /* NetBSD needs this. */
1735#include <sys/mount.h>
1736
1737#ifndef MFSNAMELEN /* NetBSD defines this. */
1738static char *
1739fstype_to_string (t)
1740 short t;
1741{
1742#ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
1743 static char *mn[] = INITMOUNTNAMES;
1744 if (t >= 0 && t <= MOUNT_MAXTYPE)
1745 return mn[t];
1746 else
1747 return "?";
1748#else /* !INITMOUNTNAMES */
1749 switch (t)
1750 {
[231]1751#ifdef MOUNT_UFS
[1]1752 case MOUNT_UFS:
1753 return _("ufs");
[231]1754#endif
1755#ifdef MOUNT_ISO9660
1756 case MOUNT_ISO9660:
1757 return _("iso9660fs");
1758#endif
1759#ifdef MOUNT_CD9660
1760 case MOUNT_CD9660:
1761 return _("cd9660");
1762#endif
1763#ifdef MOUNT_NFS
[1]1764 case MOUNT_NFS:
1765 return _("nfs");
[231]1766#endif
[1]1767#ifdef MOUNT_PC
1768 case MOUNT_PC:
1769 return _("pc");
1770#endif
1771#ifdef MOUNT_MFS
1772 case MOUNT_MFS:
1773 return _("mfs");
1774#endif
1775#ifdef MOUNT_LO
1776 case MOUNT_LO:
1777 return _("lofs");
1778#endif
1779#ifdef MOUNT_TFS
1780 case MOUNT_TFS:
1781 return _("tfs");
1782#endif
1783#ifdef MOUNT_TMP
1784 case MOUNT_TMP:
1785 return _("tmp");
1786#endif
1787#ifdef MOUNT_MSDOS
1788 case MOUNT_MSDOS:
1789 return _("msdos");
1790#endif
[231]1791#ifdef MOUNT_LFS
1792 case MOUNT_LFS:
1793 return _("lfs");
[1]1794#endif
[231]1795#ifdef MOUNT_LOFS
1796 case MOUNT_LOFS:
1797 return _("lofs");
1798#endif
1799#ifdef MOUNT_FDESC
1800 case MOUNT_FDESC:
1801 return _("fdesc");
1802#endif
1803#ifdef MOUNT_PORTAL
1804 case MOUNT_PORTAL:
1805 return _("portal");
1806#endif
1807#ifdef MOUNT_NULL
1808 case MOUNT_NULL:
1809 return _("null");
1810#endif
1811#ifdef MOUNT_UMAP
1812 case MOUNT_UMAP:
1813 return _("umap");
1814#endif
1815#ifdef MOUNT_KERNFS
1816 case MOUNT_KERNFS:
1817 return _("kernfs");
1818#endif
1819#ifdef MOUNT_PROCFS
1820 case MOUNT_PROCFS:
1821 return _("procfs");
1822#endif
1823#ifdef MOUNT_DEVFS
1824 case MOUNT_DEVFS:
1825 return _("devfs");
1826#endif
1827#ifdef MOUNT_EXT2FS
1828 case MOUNT_EXT2FS:
1829 return _("ext2fs");
1830#endif
1831#ifdef MOUNT_UNION
1832 case MOUNT_UNION:
1833 return _("union");
1834#endif
[1]1835 default:
1836 return "?";
1837 }
1838#endif /* !INITMOUNTNAMES */
1839}
1840#endif /* !MFSNAMELEN */
1841#endif /* FSTYPE_STATFS */
1842
1843#ifdef FSTYPE_AIX_STATFS /* AIX. */
1844#include <sys/vmount.h>
1845#include <sys/statfs.h>
1846
1847#define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
1848#define f_type f_vfstype
1849
1850static char *
1851fstype_to_string (t)
1852 short t;
1853{
1854 switch (t)
1855 {
1856 case MNT_AIX:
1857 return _("aix"); /* AIX 4.3: NFS filesystems are actually MNT_AIX. */
1858#ifdef MNT_NAMEFS
1859 case MNT_NAMEFS:
1860 return _("namefs");
1861#endif
1862 case MNT_NFS:
1863 return _("nfs");
1864 case MNT_JFS:
1865 return _("jfs");
1866 case MNT_CDROM:
1867 return _("cdrom");
1868#ifdef MNT_PROCFS
1869 case MNT_PROCFS:
1870 return _("procfs");
1871#endif
1872#ifdef MNT_SFS
1873 case MNT_SFS:
1874 return _("sfs");
1875#endif
1876#ifdef MNT_CACHEFS
1877 case MNT_CACHEFS:
1878 return _("cachefs");
1879#endif
1880#ifdef MNT_NFS3
1881 case MNT_NFS3:
1882 return _("nfs3");
1883#endif
1884#ifdef MNT_AUTOFS
1885 case MNT_AUTOFS:
1886 return _("autofs");
1887#endif
1888#ifdef MNT_VXFS
1889 case MNT_VXFS:
1890 return _("vxfs");
1891#endif
1892#ifdef MNT_VXODM
1893 case MNT_VXODM:
1894 return _("veritasfs");
1895#endif
1896#ifdef MNT_UDF
1897 case MNT_UDF:
1898 return _("udfs");
1899#endif
1900#ifdef MNT_NFS4
1901 case MNT_NFS4:
1902 return _("nfs4");
1903#endif
1904#ifdef MNT_RFS4
1905 case MNT_RFS4:
1906 return _("nfs4");
1907#endif
1908#ifdef MNT_CIFS
1909 case MNT_CIFS:
1910 return _("cifs");
1911#endif
1912 default:
1913 return "?";
1914 }
1915}
1916#endif /* FSTYPE_AIX_STATFS */
1917
1918#ifdef AFS
1919#include <netinet/in.h>
1920#include <afs/venus.h>
1921#if __STDC__
1922/* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
1923#undef _VICEIOCTL
1924#define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
1925#endif
1926#ifndef _IOW
1927/* AFS on Solaris 2.3 doesn't get this definition. */
1928#include <sys/ioccom.h>
1929#endif
1930
1931static int
1932in_afs (path)
1933 char *path;
1934{
1935 static char space[2048];
1936 struct ViceIoctl vi;
1937
1938 vi.in_size = 0;
1939 vi.out_size = sizeof (space);
1940 vi.out = space;
1941
1942 if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
1943 && (errno == EINVAL || errno == ENOENT))
1944 return 0;
1945 return 1;
1946}
1947#endif /* AFS */
1948
1949/* Nonzero if the current filesystem's type is known. */
1950static int fstype_known = 0;
1951
1952/* Return a static string naming the type of filesystem that the file PATH,
1953 described by STATP, is on.
1954 RELPATH is the file name relative to the current directory.
1955 Return "unknown" if its filesystem type is unknown. */
1956
1957static char *
1958filesystem_type (char * path, char * relpath, struct stat * statp)
1959{
1960 static char *current_fstype = NULL;
1961 static dev_t current_dev;
1962
1963 if (current_fstype != NULL)
1964 {
1965 if ((0 != fstype_known) && statp->st_dev == current_dev)
1966 return current_fstype; /* Cached value. */
1967 SH_FREE (current_fstype);
1968 }
1969 current_dev = statp->st_dev;
1970 current_fstype = filesystem_type_uncached (path, relpath, statp);
1971 return current_fstype;
1972}
1973
1974/* Return a newly allocated string naming the type of filesystem that the
1975 file PATH, described by STATP, is on.
1976 RELPATH is the file name relative to the current directory.
1977 Return "unknown" if its filesystem type is unknown. */
1978
1979static char *
1980filesystem_type_uncached (path, relpath, statp)
1981 char *path;
1982 char *relpath;
1983 struct stat *statp;
1984{
1985 char * type = NULL;
1986#ifdef MFSNAMELEN /* NetBSD. */
1987 static char my_tmp_type[64];
1988#endif
1989
1990#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
1991 char *table = MOUNTED;
1992 FILE *mfp;
1993 struct mntent *mnt;
1994
1995 if (path == NULL || relpath == NULL)
1996 return NULL;
1997
1998 mfp = setmntent (table, "r");
1999 if (mfp == NULL)
2000 {
2001 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
2002 _("setmntent() failed"),
2003 _("filesystem_type_uncached") );
2004 return NULL;
2005 }
2006
2007 /* Find the entry with the same device number as STATP, and return
2008 that entry's fstype. */
2009 while (type == NULL && (mnt = getmntent (mfp)) != NULL)
2010 {
[199]2011 const char *devopt;
[1]2012 dev_t dev;
2013 struct stat disk_stats;
2014
2015#ifdef MNTTYPE_IGNORE
2016 if (0 == strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
2017 continue;
2018#endif
2019
2020 /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
2021 in the options string. For older systems, we need to stat the
2022 directory that the filesystem is mounted on to get it.
2023
2024 Unfortunately, the HPUX 9.x mnttab entries created by automountq
2025 contain a dev= option but the option value does not match the
2026 st_dev value of the file (maybe the lower 16 bits match?). */
2027
2028#if !defined(hpux) && !defined(__hpux__)
2029 devopt = sl_strstr (mnt->mnt_opts, "dev=");
2030 if (devopt)
2031 {
2032 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
2033 dev = (dev_t) xatoi (devopt + 6);
2034 else
2035 dev = (dev_t) xatoi (devopt + 4);
2036 }
2037 else
2038#endif /* not hpux */
2039 {
2040 if (stat (mnt->mnt_dir, &disk_stats) == -1)
2041 {
[252]2042 char errmsg[256];
2043 int elevel = SH_ERR_ERR;
2044 size_t tlen = strlen(mnt->mnt_dir);
2045 if (tlen >= 6 && 0 == strcmp(&((mnt->mnt_dir)[tlen-6]), _("/.gvfs")))
2046 elevel = SH_ERR_NOTICE;
2047 sl_snprintf(errmsg, sizeof(errmsg), _("stat(%s) failed"),
2048 mnt->mnt_dir);
2049 sh_error_handle (elevel, FIL__, __LINE__, 0, MSG_E_SUBGEN,
2050 errmsg,
[1]2051 _("filesystem_type_uncached") );
2052 return NULL;
2053 }
2054 dev = disk_stats.st_dev;
2055 }
2056
2057 if (dev == statp->st_dev)
2058 {
2059 /* check for the "nosuid" option
2060 */
[61]2061#ifdef HAVE_HASMNTOPT
[119]2062 if (NULL == hasmntopt(mnt, "nosuid") || (ShSuidchkNosuid == S_TRUE))
[1]2063 type = mnt->mnt_type;
2064 else
[61]2065 type = _("nosuid"); /* hasmntopt (nosuid) */
2066#else
2067 type = mnt->mnt_type;
2068#endif
[1]2069 }
2070 }
2071
2072 if (endmntent (mfp) == 0)
2073 {
2074 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
2075 _("endmntent() failed"),
2076 _("filesystem_type_uncached") );
2077 }
2078#endif
2079
2080#ifdef FSTYPE_GETMNT /* Ultrix. */
2081 int offset = 0;
2082 struct fs_data fsd;
2083
2084 if (path == NULL || relpath == NULL)
2085 return NULL;
2086
2087 while (type == NULL
2088 && getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 0) > 0)
2089 {
2090 if (fsd.fd_req.dev == statp->st_dev)
2091 type = gt_names[fsd.fd_req.fstype];
2092 }
2093#endif
2094
2095#ifdef FSTYPE_USG_STATFS /* SVR3. */
2096 struct statfs fss;
2097 char typebuf[FSTYPSZ];
2098
2099 if (path == NULL || relpath == NULL)
2100 return NULL;
2101
2102 if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
2103 {
2104 /* Don't die if a file was just removed. */
2105 if (errno != ENOENT)
2106 {
2107 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
2108 _("statfs() failed"),
2109 _("filesystem_type_uncached") );
2110 return NULL;
2111 }
2112 }
2113 else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
2114 type = typebuf;
2115#endif
2116
2117#ifdef FSTYPE_STATVFS /* SVR4. */
2118 struct statvfs fss;
2119
2120 if (path == NULL || relpath == NULL)
2121 return NULL;
2122
2123 if (statvfs (relpath, &fss) == -1)
2124 {
2125 /* Don't die if a file was just removed. */
2126 if (errno != ENOENT)
2127 {
2128 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
2129 _("statvfs() failed"),
2130 _("filesystem_type_uncached") );
2131 return NULL;
2132 }
2133 }
2134 else
2135 {
2136 type = fss.f_basetype;
2137
2138 /* patch by Konstantin Khrooschev <nathoo@co.ru>
2139 */
[119]2140 if( (fss.f_flag & ST_NOSUID) && (ShSuidchkNosuid == S_FALSE))
[1]2141 type = _("nosuid");
2142 }
2143 (void) statp; /* fix compiler warning */
2144#endif
2145
2146#ifdef FSTYPE_STATFS /* 4.4BSD. */
2147 struct statfs fss;
2148 char *p;
2149#if defined(MNT_VISFLAGMASK) && defined(HAVE_STRUCT_STATFS_F_FLAGS)
2150 int flags;
2151#endif
2152 /* char * sh_dirname(const char *path); */
2153
2154 if (path == NULL || relpath == NULL)
2155 return NULL;
2156
2157 if (S_ISLNK (statp->st_mode))
2158 p = sh_dirname (relpath);
2159 else
2160 p = relpath;
2161
2162 if (statfs (p, &fss) == -1)
2163 {
2164 /* Don't die if symlink to nonexisting file, or a file that was
2165 just removed. */
2166 if (errno != ENOENT)
2167 {
2168 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
2169 _("statfs() failed"),
2170 _("filesystem_type_uncached") );
2171 return NULL;
2172 }
2173 }
2174 else
2175 {
2176
2177#ifdef MFSNAMELEN /* NetBSD. */
2178 /* MEMORY LEAK !!!
2179 * type = sh_util_strdup (fss.f_fstypename);
2180 */
2181 sl_strlcpy (my_tmp_type, fss.f_fstypename, 64);
2182 type = my_tmp_type;
2183#else
2184 type = fstype_to_string (fss.f_type);
2185#endif
2186
2187#ifdef HAVE_STRUCT_STATFS_F_FLAGS
2188#ifdef MNT_VISFLAGMASK
2189 flags = fss.f_flags & MNT_VISFLAGMASK;
[119]2190 if ((flags & MNT_NOSUID) && (ShSuidchkNosuid == S_FALSE))
[1]2191#else
[119]2192 if ((fss.f_flags & MNT_NOSUID) && (ShSuidchkNosuid == S_FALSE))
[1]2193#endif
2194 type = _("nosuid");
2195#endif
2196 }
2197 if (p != relpath)
2198 SH_FREE (p);
2199#endif
2200
2201#ifdef AFS
2202 if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
2203 type = "afs";
2204#endif
2205
2206 /* An unknown value can be caused by an ENOENT error condition.
2207 Don't cache those values. */
2208 fstype_known = (int)(type != NULL);
2209
2210 return sh_util_strdup (type ? type : "unknown");
2211}
2212
2213#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
2214/* Return the value of the hexadecimal number represented by CP.
2215 No prefix (like '0x') or suffix (like 'h') is expected to be
2216 part of CP. */
2217
2218static int
2219xatoi (cp)
[199]2220 const char *cp;
[1]2221{
2222 int val;
2223
2224 val = 0;
2225 while (*cp != '\0')
2226 {
2227 /*@+charint@*/
2228 if (*cp >= 'a' && *cp <= 'f')
2229 val = val * 16 + *cp - 'a' + 10;
2230 else if (*cp >= 'A' && *cp <= 'F')
2231 val = val * 16 + *cp - 'A' + 10;
2232 else if (*cp >= '0' && *cp <= '9')
2233 val = val * 16 + *cp - '0';
2234 else
2235 break;
2236 /*@-charint@*/
2237 cp++;
2238 }
2239 return val;
2240}
2241#endif
2242
2243
2244
2245#endif
2246
2247
2248/* #ifdef SH_USE_UTMP */
2249#endif
2250
2251
2252
Note: See TracBrowser for help on using the repository browser.