source: trunk/src/sh_suidchk.c@ 583

Last change on this file since 583 was 583, checked in by katerina, 33 hours ago

Fix for ticket #471 (autoreconf throws warnings/errors).

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