source: trunk/src/sh_suidchk.c@ 592

Last change on this file since 592 was 592, checked in by katerina, 4 days ago

Fixes for compiler warnings.

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