source: trunk/src/slib.c@ 270

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

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

File size: 69.8 KB
Line 
1#include "config_xor.h"
2
3#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE)
4#define _XOPEN_SOURCE 600
5#define _BSD_SOURCE
6#endif
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <stdarg.h>
11#include <string.h>
12#include <limits.h>
13#ifdef HAVE_STDINT_H
14/* for SIZE_MAX */
15#include <stdint.h>
16#endif
17
18#include <unistd.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <fcntl.h>
22#include <signal.h>
23
24#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE)
25#include <sys/mman.h>
26#endif
27
28#if TIME_WITH_SYS_TIME
29#include <sys/time.h>
30#include <time.h>
31#else
32#if HAVE_SYS_TIME_H
33#include <sys/time.h>
34#else
35#include <time.h>
36#endif
37#endif
38
39#ifdef HAVE_MEMORY_H
40#include <memory.h>
41#endif
42#ifdef HAVE_SYS_SELECT_H
43#include <sys/select.h>
44#endif
45
46#ifndef FD_SET
47#define NFDBITS 32
48#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
49#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
50#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
51#endif /* !FD_SET */
52#ifndef FD_SETSIZE
53#define FD_SETSIZE 32
54#endif
55#ifndef FD_ZERO
56#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
57#endif
58
59#define SH_REAL_SET
60
61#include "slib.h"
62#include "sh_calls.h"
63#define SH_NEED_PWD_GRP 1
64#include "sh_static.h"
65#include "sh_pthread.h"
66#include "sh_string.h"
67
68#undef FIL__
69#define FIL__ _("slib.c")
70
71const uid_t sh_uid_neg = ((uid_t) -1);
72const gid_t sh_gid_neg = ((gid_t) -1);
73
74#undef BREAKEXIT
75#if defined(SCREW_IT_UP) && defined(__linux__) && defined(__i386__)
76
77#ifdef SH_DEBUG
78#define BREAKEXIT(expr) \
79 do { \
80 int ixi; \
81 for (ixi = 0; ixi < 8; ++ixi) { \
82 if ((*(volatile unsigned *)((unsigned) expr + ixi) & 0xff) == 0xcc) \
83 { dlog(0, FIL__, __LINE__, _("BREAKEXIT")); _exit(EXIT_FAILURE); } \
84 } \
85 } \
86 while (1 == 0)
87#else
88#define BREAKEXIT(expr) \
89 do { \
90 int ixi; \
91 for (ixi = 0; ixi < 8; ++ixi) { \
92 if ((*(volatile unsigned *)((unsigned) expr + ixi) & 0xff) == 0xcc) \
93 _exit(EXIT_FAILURE); \
94 } \
95 } \
96 while (1 == 0)
97#endif
98
99#else
100#define BREAKEXIT(expr)
101#endif
102
103/****************************************************************
104 *
105 * The debug/trace subsystem
106 *
107 ****************************************************************/
108
109int slib_do_trace = 0;
110int slib_trace_fd = -1;
111
112static char trace_log[256] = { '\0' };
113static int trace_level = 0;
114static FILE * trace_fp = NULL;
115
116int sl_trace_use (const char * dummy)
117{
118 (void) dummy;
119 slib_do_trace = 1;
120 return 0;
121}
122
123int sl_trace_file (const char * str)
124{
125 if (!str)
126 return -1;
127 if (str[0] != '/')
128 return -1;
129 sl_strlcpy(trace_log, str, 256);
130 return 0;
131}
132
133FILE * sl_tracefile_open(const char * file, const char * mode)
134{
135 FILE * xp = NULL;
136 slib_trace_fd = open(file, O_WRONLY|O_CREAT|O_APPEND, 0600);
137 if (slib_trace_fd >= 0)
138 xp = fdopen(slib_trace_fd, mode);
139 return xp;
140}
141
142void sl_trace_in(const char * str, const char * file, int line)
143{
144 int i;
145 if (trace_log[0] == '\0')
146 {
147 fprintf(stderr, "++ ");
148 for (i = 0; i < trace_level; ++i)
149 fprintf(stderr, ". ");
150 fprintf(stderr, "[%2d] %s \t - File %c%s%c at line %d\n",
151 trace_level, str, 0x22, file, 0x22, line);
152 }
153 else if (!sl_is_suid())
154 {
155 if (!trace_fp)
156 trace_fp = sl_tracefile_open(trace_log, "a");
157 if (trace_fp)
158 {
159 fprintf(trace_fp, "++ ");
160 for (i = 0; i < trace_level; ++i)
161 fprintf(trace_fp, ". ");
162 fprintf(trace_fp, "[%2d] %s \t - File %c%s%c at line %d\n",
163 trace_level, str, 0x22, file, 0x22, line);
164 fflush(trace_fp);
165 }
166 else
167 {
168 perror(_("sl_trace_in: fopen"));
169 _exit(1);
170 }
171 }
172 ++trace_level;
173}
174
175void sl_trace_out(const char * str, const char * file, int line)
176{
177 int i;
178
179 --trace_level; if (trace_level < 0) trace_level = 0;
180
181 if (trace_log[0] == '\0')
182 {
183 fprintf(stderr, "-- ");
184 for (i = 0; i < trace_level; ++i)
185 fprintf(stderr, ". ");
186 fprintf(stderr, _("[%2d] %s \t - File %c%s%c at line %d\n"),
187 trace_level, str, 0x22, file, 0x22, line);
188 }
189 else if (!sl_is_suid())
190 {
191 if (!trace_fp)
192 trace_fp = sl_tracefile_open(trace_log, "a");
193 if (trace_fp)
194 {
195 fprintf(trace_fp, "-- ");
196 for (i = 0; i < trace_level; ++i)
197 fprintf(trace_fp, ". ");
198 fprintf(trace_fp, _("[%2d] %s \t - File %c%s%c at line %d\n"),
199 trace_level, str, 0x22, file, 0x22, line);
200 fflush(trace_fp);
201 }
202 else
203 {
204 perror(_("sl_trace_out: fopen"));
205 _exit(1);
206 }
207 }
208}
209
210extern int sh_log_console (const char * msg);
211
212static int dlogActive = 0;
213
214/* this is called from sh_error_setprint()
215 */
216void dlog_set_active(int flag)
217{
218 dlogActive = flag;
219}
220
221/* flag = 0 debug messages
222 * = 1 descriptive error messages
223 * = 3 backtrace
224 */
225int dlog (int flag, const char * file, int line, const char *fmt, ...)
226{
227 va_list ap;
228 char val[81];
229 char msg[512];
230 char tmp[512];
231 int retval = 0;
232 int i;
233
234#ifdef SH_STEALTH
235 /*
236 * do not even print descriptive failure messages in stealth mode
237 */
238 if (dlogActive == 0)
239 return 0;
240 if (dlogActive == 1 && flag == 0) /* debug requires debug level */
241 return 0;
242#else
243 if (dlogActive <= 1 && flag == 0) /* debug requires debug level */
244 return 0;
245#endif
246
247 if (flag == 1)
248 {
249 sl_snprintf (val, 81, _("\n--------- %10s "), file);
250 sl_strlcpy (msg, val, 80);
251 sl_snprintf (val, 81, _(" --- %6d ---------\n"), line);
252 sl_strlcat (msg, val, 80);
253 sh_log_console (msg);
254 }
255
256 va_start (ap, fmt);
257 if (flag == 1)
258 sl_strlcpy(tmp, fmt, 512);
259 else
260 sl_strlcpy(tmp, fmt, 256);
261 retval = sl_strlen(tmp);
262 if (retval > 0 && tmp[retval-1] == '\n')
263 tmp[retval-1] = '\0';
264 retval = 0;
265 if (flag == 1)
266 {
267 sl_vsnprintf (msg, 511, tmp, ap);
268 }
269 else
270 {
271 sl_strlcpy (msg, "## ", 256);
272 for (i = 0; i < trace_level; ++i)
273 sl_strlcat (msg, ". ", 256);
274 sprintf (val, _("[%2d] "), trace_level);
275 sl_strlcat (msg, val, 256);
276 sl_vsnprintf (&msg[sl_strlen(msg)], 255, tmp, ap);
277 sl_snprintf (tmp, 255, _(" \t - File %c%s%c at line %d"),
278 0x22, file, 0x22, line);
279 sl_strlcat (msg, tmp, 512);
280 }
281 va_end (ap);
282 if (flag != 0 || sl_is_suid())
283 retval = sh_log_console (msg);
284 else
285 {
286 if (trace_log[0] == '\0')
287 {
288 /* sh_log_console (msg); */
289 fprintf(stderr, "%s\n", msg);
290 }
291 else
292 {
293 if (!trace_fp)
294 trace_fp = sl_tracefile_open(trace_log, "a");
295 if (trace_fp)
296 {
297 fprintf(trace_fp, "%s\n", msg);
298 }
299 else
300 {
301 perror(_("dlog: fopen"));
302 _exit(1);
303 }
304 }
305 }
306 if (flag == 1)
307 sh_log_console (_("\n----------------------------------------------\n"));
308 return retval;
309}
310
311extern char aud_err_message[64];
312static char alt_err_message[64];
313char * sl_get_errmsg()
314{
315 if (aud_err_message[0] == '\0')
316 {
317 sl_strlcpy(alt_err_message, sl_error_string(sl_errno), 64);
318 return &alt_err_message[0];
319 }
320 return &aud_err_message[0];
321}
322
323
324#if defined(SL_DEBUG)
325#define SL_MAX_MYSTACK 128
326
327static char sl_mystack[SL_MAX_MYSTACK][32];
328static int sl_mystack_count = 0;
329
330void sl_stack_push(char * c, char * file, int line )
331{
332 if (slib_do_trace)
333 sl_trace_in(c, file, line);
334 if (c && sl_mystack_count < SL_MAX_MYSTACK)
335 {
336 strncpy(sl_mystack[sl_mystack_count], c, 31);
337 sl_mystack[sl_mystack_count][31] = '\0';
338 ++sl_mystack_count;
339 /*
340 fprintf(stderr, "#%03d %s\n", sl_mystack_count,
341 sl_mystack[sl_mystack_count-1]);
342 */
343 }
344 return;
345}
346
347void sl_stack_pop(char * c, char * file, int line)
348{
349 if (slib_do_trace)
350 sl_trace_out(c, file, line);
351 if (sl_mystack_count > 0)
352 {
353 /*
354 fprintf(stderr, " <- #%03d %s\n", sl_mystack_count,
355 sl_mystack[sl_mystack_count-1]);
356 */
357 --sl_mystack_count;
358 }
359 return;
360}
361
362void sl_stack_print()
363{
364 int i;
365 /* FILE * dfile; */
366
367 if (sl_mystack_count > 0)
368 {
369 sh_log_console(_("\nBacktrace:\n"));
370 /* dlog(3, FIL__, __LINE__, _("\nBacktrace:\n")); */
371 for (i = 0; i < sl_mystack_count; ++i)
372 sh_log_console(sl_mystack[i]);
373 /* dlog(3, FIL__, __LINE__, _("#%03d %s\n"), i, sl_mystack[i]); */
374 }
375 return;
376}
377
378#endif
379
380
381/*
382 * The global errno.
383 * On error, this is set to the return value of the function.
384 */
385long int sl_errno;
386
387
388/* ----------------------------------------------------------------
389 *
390 * Capability routines
391 *
392 * ---------------------------------------------------------------- */
393
394int sl_useCaps = 0;
395
396#ifdef FANCY_LIBCAP
397#include <sys/capability.h>
398
399/*
400 * While these routines are tested and work, we don't use POSIX
401 * capabilities, as they don't seem to be useful (root can write
402 * to root-owned files anyway). Things would be more interesting
403 * if we could switch to a non-root UID with just a few capabilities
404 * enabled.
405 */
406int sl_drop_cap ()
407{
408 int error;
409 cap_t caps;
410 cap_flag_t capflag;
411 cap_flag_value_t capfval = CAP_CLEAR;
412 cap_value_t capvals_e[] =
413 {
414 CAP_CHOWN, CAP_FOWNER, CAP_FSETID,
415 CAP_LINUX_IMMUTABLE, CAP_MKNOD, CAP_NET_ADMIN,
416 CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW,
417 CAP_SYS_ADMIN, CAP_SYS_BOOT, CAP_SYS_CHROOT,
418 CAP_SYS_PACCT, CAP_SYS_PTRACE, CAP_SYS_RAWIO,
419 CAP_SYS_RESOURCE, CAP_SYS_TIME, CAP_SYS_TTY_CONFIG,
420 CAP_SETGID, CAP_SETUID, CAP_KILL,
421 CAP_DAC_OVERRIDE,
422#if !defined(WITH_MESSAGE_QUEUE)
423 CAP_IPC_OWNER,
424#endif
425 CAP_SYS_MODULE, CAP_LEASE
426 };
427 cap_value_t capvals_p[] =
428 {
429 CAP_CHOWN, CAP_LEASE, CAP_FSETID,
430 CAP_LINUX_IMMUTABLE, CAP_MKNOD, CAP_NET_ADMIN,
431 CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW,
432 CAP_SYS_ADMIN, CAP_SYS_BOOT, CAP_SYS_CHROOT,
433 CAP_SYS_PACCT, CAP_SYS_PTRACE, CAP_SYS_RAWIO,
434 CAP_SYS_RESOURCE, CAP_SYS_TIME, CAP_SYS_TTY_CONFIG,
435#if !defined(WITH_EXTERNAL) && !defined(HAVE_UNIX_RANDOM)
436 CAP_SETGID, CAP_SETUID, CAP_KILL,
437#endif
438#if !defined(SH_USE_SUIDCHK)
439 CAP_DAC_OVERRIDE, CAP_FOWNER,
440#endif
441#if !defined(WITH_MESSAGE_QUEUE)
442 CAP_IPC_OWNER,
443#endif
444 CAP_SYS_MODULE
445 };
446
447 if (0 == sl_useCaps) /* 0 = S_FALSE */
448 {
449 return 0;
450 }
451
452 if(NULL == (caps = cap_get_proc()))
453 {
454 return errno;
455 }
456
457 capflag = CAP_EFFECTIVE;
458 if (0 != cap_set_flag(caps, capflag, sizeof(capvals_e)/sizeof(cap_value_t),
459 capvals_e, capfval))
460 {
461 error = errno;
462 cap_free(caps);
463 return error;
464 }
465 if (0 != cap_set_proc(caps))
466 {
467 error = errno;
468 cap_free(caps);
469 return error;
470 }
471
472 capflag = CAP_PERMITTED;
473 if (0 != cap_set_flag(caps, capflag, sizeof(capvals_p)/sizeof(cap_value_t),
474 capvals_p, capfval))
475 {
476 error = errno;
477 cap_free(caps);
478 return error;
479 }
480 if (0 != cap_set_proc(caps))
481 {
482 error = errno;
483 cap_free(caps);
484 return error;
485 }
486 cap_free(caps);
487 return 0;
488}
489
490int sl_drop_cap_int(int what)
491{
492#if defined(SL_DEBUG)
493 char * captext;
494#endif
495 cap_flag_t capflag = CAP_EFFECTIVE;
496 cap_flag_value_t capfval = CAP_CLEAR;
497 cap_value_t capvals_a[] = { CAP_SETGID, CAP_SETUID, CAP_KILL };
498 cap_value_t capvals_b[] = { CAP_DAC_OVERRIDE, CAP_FOWNER };
499 cap_value_t * capvals;
500 int nvals;
501 int error = 0;
502 cap_t caps = cap_get_proc();
503
504 if (0 == sl_useCaps) /* 0 = S_FALSE */
505 {
506 return 0;
507 }
508
509 if (caps == NULL)
510 {
511 return errno;
512 }
513
514 switch (what) {
515 case 1:
516 capvals = capvals_a;
517 nvals = 3;
518 capfval = CAP_CLEAR;
519 break;
520 case 2:
521 capvals = capvals_a;
522 nvals = 3;
523 capfval = CAP_SET;
524 break;
525 case 3:
526 capvals = capvals_b;
527 nvals = 2;
528 capfval = CAP_CLEAR;
529 break;
530 case 4:
531 capvals = capvals_b;
532 nvals = 2;
533 capfval = CAP_SET;
534 break;
535 default:
536 return (0);
537 }
538
539 if (0 != cap_set_flag(caps, capflag, nvals, capvals, capfval))
540 {
541 error = errno;
542 cap_free(caps);
543 return error;
544 }
545 if (0 != cap_set_proc(caps))
546 {
547 error = errno;
548 cap_free(caps);
549 return error;
550 }
551#if defined(SL_DEBUG)
552 captext = cap_to_text(caps, NULL);
553 TPT(( 0, FIL__, __LINE__, _("msg=<cap_int %d: %s>\n"), what, captext));
554 cap_free(captext);
555#endif
556 cap_free(caps);
557 return 0;
558}
559
560int sl_drop_cap_sub() { return sl_drop_cap_int(1); }
561int sl_get_cap_sub() { return sl_drop_cap_int(2); }
562int sl_drop_cap_qdel() { return sl_drop_cap_int(3); }
563int sl_get_cap_qdel() { return sl_drop_cap_int(4); }
564
565#else
566int sl_drop_cap () { return 0; }
567int sl_drop_cap_sub() { return 0; }
568int sl_get_cap_sub() { return 0; }
569int sl_drop_cap_qdel() { return 0; }
570int sl_get_cap_qdel() { return 0; }
571#endif
572
573/* ----------------------------------------------------------------
574 *
575 * String handling routines
576 *
577 * ---------------------------------------------------------------- */
578
579/*
580 * Have memset in a different translation unit (i.e. this) to prevent
581 * it to get optimized away
582 */
583void *sl_memset(void *s, int c, size_t n)
584{
585 return memset(s, c,n);
586}
587
588
589#if !defined (VA_COPY)
590#if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32))
591#define VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
592#elif defined (VA_COPY_AS_ARRAY)
593#define VA_COPY(ap1, ap2) memmove ((ap1), (ap2), sizeof (va_list))
594#else /* va_list is a pointer */
595#define VA_COPY(ap1, ap2) ((ap1) = (ap2))
596#endif
597#endif
598
599#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
600static
601size_t sl_printf_count (const char * fmt, va_list vl)
602{
603 size_t length = 1;
604 int fini = 0;
605 int islong = 0;
606 int islonglong = 0;
607 int islongdouble = 0;
608 char * string_arg;
609
610 SL_ENTER(_("sl_printf_count"));
611
612 if (fmt == NULL)
613 SL_IRETURN(SL_ENULL, _("sl_printf_count"));
614
615 while (*fmt) {
616
617 if ( (*fmt) == '%' ) { /* a format specifier */
618
619 fmt++; /* point to first char after '%' */
620
621 fini = 0;
622 islong = 0;
623 islongdouble = 0;
624
625 while (*fmt && (fini == 0) ) {
626
627 switch (*fmt) {
628
629 case '*': /* field width supplied by an integer */
630 length = length + va_arg (vl, int);
631 ++fmt;
632 break;
633 case '1':
634 case '2':
635 case '3':
636 case '4':
637 case '5':
638 case '6':
639 case '7':
640 case '8':
641 case '9':
642 length = length + strtol (fmt, (char**) &fmt, 10);
643 /* strtol makes FastForward to first invalid char */
644 break;
645
646 case 'l': /* 'long' modifier */
647 if (islong == 0)
648 islong = 1;
649 else
650 {
651 islonglong = 1;
652 islong = 0;
653 }
654 ++fmt;
655 break;
656
657 case 'L': /* 'long double' modifier */
658#ifdef HAVE_LONG_DOUBLE
659 islongdouble = 1;
660#else
661 islong = 1;
662#endif
663 ++fmt;
664 break;
665
666 case 'd':
667 case 'i':
668 case 'o':
669 case 'u':
670 case 'x':
671 case 'X':
672 if (islonglong == 1)
673#ifdef HAVE_LONG_LONG
674 (void) va_arg (vl, long long);
675#else
676 (void) va_arg (vl, long);
677#endif
678 else if (islong == 1)
679 (void) va_arg (vl, long);
680 else
681 (void) va_arg (vl, int);
682 islong = 0;
683 islonglong = 0;
684 length = length + 24;
685 ++fmt;
686 fini = 1;
687 break;
688
689 case 'D':
690 case 'O':
691 case 'U':
692 (void) va_arg (vl, long);
693 length = length + 24;
694 fmt++;
695 fini = 1;
696 break;
697
698 case 'e':
699 case 'E':
700 case 'f':
701 case 'g':
702#ifdef HAVE_LONG_DOUBLE
703 if (islongdouble == 1) {
704 (void) va_arg (vl, long double);
705 islongdouble = 0;
706 length = length + 20;
707 }
708 else
709#endif
710 (void) va_arg (vl, double);
711 length = length + 20;
712 fini = 1;
713 ++fmt;
714 break;
715
716 case 's':
717 string_arg = va_arg (vl, char *);
718 if (string_arg != NULL)
719 length = length + sl_strlen (string_arg);
720 else
721 length = length + 16;
722 fini = 1;
723 ++fmt;
724 break;
725
726 case 'c':
727 (void) va_arg (vl, int);
728 length = length + 1;
729 fini = 1;
730 ++fmt;
731 break;
732
733 case 'p':
734 case 'n':
735 (void) va_arg (vl, void * );
736 length = length + 32;
737 fini = 1;
738 ++fmt;
739 break;
740
741 case '%': /* %% will print '%' */
742 length = length + 1;
743 fini = 1;
744 ++fmt;
745 break;
746
747 default:
748 length = length + 1;
749 ++fmt;
750 break;
751
752 } /* end switch */
753 }
754 /* end parsing a single format specifier */
755 } else {
756 length = length + 1;
757 fmt++;
758 }
759 }
760 SL_IRETURN(length, _("sl_printf_count"));
761}
762#endif /* #ifndef HAVE_VSNPRINTF */
763
764/*
765 * An implementation of vsnprintf. va_start/va_end are in the caller
766 * function.
767 * Returns C99 (#bytes that would heve been written) on success.
768 */
769int sl_vsnprintf(char *str, size_t n,
770 const char *format, va_list vl )
771{
772 int len = 0;
773#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
774 size_t total;
775 va_list vl2;
776#endif
777
778 SL_ENTER(_("sl_vsnprintf"));
779 if (str == NULL || format == NULL)
780 SL_IRETURN(0, _("sl_vsnprintf"));
781
782#if defined(HAVE_VSNPRINTF) && !defined(HAVE_BROKEN_VSNPRINTF)
783 len = vsnprintf (str, n, format, vl); /* flawfinder: ignore */
784 str[n-1] = '\0';
785#else
786 VA_COPY (vl2, vl); /* save the argument list */
787 total = sl_printf_count (format, vl);
788 len = (int) total;
789 if (total < n)
790 {
791 /* flawfinder: ignore */
792 vsprintf (str, format, vl2); /* program has checked that it fits */
793 str[n-1] = '\0';
794 }
795 else
796 {
797 sl_strlcpy (str, format, n);
798 va_end(vl2);
799 SL_IRETURN(len, _("sl_vsnprintf"));
800 }
801 va_end(vl2);
802#endif
803 SL_IRETURN(len, _("sl_vsnprintf"));
804}
805
806/*
807 * An implementation of snprintf.
808 * Returns SL_ENONE on success.
809 * ENULL: src || format == NULL
810 * ERANGE: n out of range
811 * ETRUNC: truncated (unimplemented)
812 */
813int sl_snprintf(char *str, size_t n,
814 const char *format, ... )
815{
816 va_list vl;
817#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
818 size_t total = 0;
819 va_list vl2;
820#endif
821
822 SL_ENTER(_("sl_snprintf"));
823 if (str == NULL || format == NULL)
824 SL_IRETURN(SL_ENULL, _("sl_snprintf"));
825
826 va_start (vl, format);
827#if defined(HAVE_VSNPRINTF) && !defined(HAVE_BROKEN_VSNPRINTF)
828 /* flawfinder: ignore */
829 vsnprintf (str, n, format, vl);
830 str[n-1] = '\0';
831#else
832 VA_COPY (vl2, vl); /* save the argument list */
833 total = sl_printf_count (format, vl);
834 if (total < n)
835 {
836 /* flawfinder: ignore */
837 vsprintf (str, format, vl2); /* program has checked that it fits */
838 str[n-1] = '\0';
839 }
840 else
841 {
842 sl_strlcpy (str, format, n);
843 va_end(vl2);
844 va_end(vl);
845 SL_IRETURN(SL_ETRUNC, _("sl_snprintf"));
846 }
847 va_end(vl2);
848#endif
849 va_end(vl);
850 SL_IRETURN(SL_ENONE, _("sl_snprintf"));
851}
852
853/*
854 * Appends src to string dst of size siz (unlike strncat, siz is the
855 * full size of dst, not space left). At most siz-1 characters
856 * will be copied. Always NUL terminates (unless siz == 0).
857 * Returns SL_NONE on success, errcode on failure.
858 *
859 * ENULL: dst == NULL
860 * ERANGE: siz out of range
861 * ETRUNC: src truncated
862 */
863int sl_strlcat(char * dst, /*@null@*/const char *src, size_t siz)
864{
865 register size_t dst_end;
866 register size_t dst_free;
867
868 register char * p;
869 register const char * q;
870
871 if (!(dst == NULL || src == NULL || *src == '\0'))
872 {
873 if (siz > 0)
874 {
875
876 /* How much free space do we have ?
877 */
878 dst_end = strlen(dst);
879 dst_free = siz - dst_end - 1;
880
881 p = &dst[dst_end];
882 q = src;
883
884 while (dst_free > 0 && *q != '\0')
885 {
886 *p++ = *q++;
887 --dst_free;
888 }
889
890 /* NULL terminate dst.
891 */
892 *p = '\0';
893
894 if (*q == '\0')
895 return SL_ENONE;
896 else
897 return SL_ETRUNC;
898 }
899 }
900 return SL_ENONE;
901}
902
903/*
904 * An alternative implementation of the OpenBSD strlcpy() function.
905 *
906 * Copy src to string dst of size siz. At most siz-1 characters
907 * will be copied. Always NUL terminates (unless siz == 0).
908 * Returns SL_NONE on success, errcode on failure.
909 *
910 * ENULL: dst == NULL
911 * ERANGE: siz out of range
912 * ETRUNC: src truncated
913 */
914int sl_strlcpy(char * dst, /*@null@*/const char * src, size_t siz)
915{
916 /* SL_ENTER(_("sl_strlcpy")); */
917
918 if (!((dst == NULL) || (src == NULL)))
919 {
920 if (siz > 0) {
921 /* copy siz-1 characters
922 */
923 (void) strncpy(dst, src, siz-1);
924
925 /* NULL terminate
926 */
927 dst[siz-1] = '\0';
928 }
929 return SL_ENONE;
930 }
931 else if (src == NULL)
932 {
933 if (siz > 0)
934 dst[0] = '\0';
935 return SL_ENONE;
936 }
937 else
938 {
939 return SL_ENULL;
940 }
941}
942
943/*
944 * A robust drop-in replacement of strncpy. strlcpy is preferable.
945 */
946char * sl_strncpy(char *dst, const char *src, size_t size)
947{
948
949#ifdef SL_FAIL_ON_ERROR
950 SL_REQUIRE(dst != NULL, _("dst != NULL"));
951 SL_REQUIRE(src != NULL, _("src != NULL"));
952 SL_REQUIRE(size > 0, _("size > 0"));
953#endif
954
955 if (dst == NULL)
956 {
957 sl_errno = SL_ENULL;
958 return (NULL);
959 }
960 if (size < 1)
961 {
962 sl_errno = SL_ERANGE;
963 return (dst);
964 }
965 if (!src)
966 {
967 sl_errno = SL_ENULL;
968 dst[0] = '\0';
969 }
970 else if (src[0] == '\0')
971 dst[0] = '\0';
972 else
973 strncpy(dst, src, size);
974
975 if (sl_strlen(src) >= size)
976 {
977 errno = ENOSPC;
978 dst[size-1] = '\0';
979 }
980 return (dst);
981}
982
983/*
984 * A robust drop-in replacement of strncat. strlcat is preferable.
985 */
986char * sl_strncat(char *dst, const char *src, size_t n)
987{
988#ifdef SL_FAIL_ON_ERROR
989 SL_REQUIRE(dst != NULL, _("dst != NULL"));
990 SL_REQUIRE(src != NULL, _("src != NULL"));
991 SL_REQUIRE(n > 0, _("n > 0"));
992#endif
993
994 if (dst == NULL)
995 {
996 sl_errno = SL_ENULL;
997 return (NULL);
998 }
999 if (n < 1)
1000 {
1001 sl_errno = SL_ERANGE;
1002 return (dst);
1003 }
1004 if (!src)
1005 {
1006 sl_errno = SL_ENULL;
1007 return (dst);
1008 }
1009 else if (src[0] == '\0')
1010 dst[0] = '\0';
1011 else
1012 strncat(dst, src, n);
1013
1014 return (dst);
1015}
1016
1017#include <ctype.h>
1018int sl_strcasecmp(const char * one, const char * two)
1019{
1020#ifdef SL_FAIL_ON_ERROR
1021 SL_REQUIRE (one != NULL, _("one != NULL"));
1022 SL_REQUIRE (two != NULL, _("two != NULL"));
1023#endif
1024
1025 if (one && two)
1026 {
1027 do {
1028 if (*one && *two)
1029 {
1030 if (tolower(*one) == tolower(*two))
1031 {
1032 ++one; ++two;
1033 }
1034 else if (tolower(*one) < tolower(*two))
1035 return -1;
1036 else
1037 return 1;
1038 }
1039 else if (*one == '\0' && *two == '\0')
1040 return 0;
1041 else if (*one == '\0')
1042 return -1;
1043 else
1044 return 1;
1045 } while (1 == 1);
1046 }
1047 else if (one == NULL && two != NULL)
1048 return -1;
1049 else if (one != NULL && two == NULL)
1050 return 1;
1051 else
1052 return -7; /* default to not equal */
1053}
1054
1055int sl_strcmp(const char * a, const char * b)
1056{
1057#ifdef SL_FAIL_ON_ERROR
1058 SL_REQUIRE (a != NULL, _("a != NULL"));
1059 SL_REQUIRE (b != NULL, _("b != NULL"));
1060#endif
1061
1062 if (a != NULL && b != NULL)
1063 return (strcmp(a, b));
1064 else if (a == NULL && b != NULL)
1065 return (-1);
1066 else if (a != NULL && b == NULL)
1067 return (1);
1068 else
1069 return (-7); /* default to not equal */
1070}
1071
1072int sl_strncmp(const char * a, const char * b, size_t n)
1073{
1074#ifdef SL_FAIL_ON_ERROR
1075 SL_REQUIRE (a != NULL, _("a != NULL"));
1076 SL_REQUIRE (b != NULL, _("b != NULL"));
1077 SL_REQUIRE (n > 0, _("n > 0"));
1078#endif
1079
1080 if (a != NULL && b != NULL)
1081 return (strncmp(a, b, n));
1082 else if (a == NULL && b != NULL)
1083 return (-1);
1084 else if (a != NULL && b == NULL)
1085 return (1);
1086 else
1087 return (-7); /* default to not equal */
1088}
1089
1090/* string searching
1091 */
1092
1093char * sl_strstr (const char * haystack, const char * needle)
1094{
1095#ifndef HAVE_STRSTR
1096 unsigned int i;
1097 size_t needle_len;
1098 size_t haystack_len;
1099#endif
1100
1101 if (haystack == NULL || needle == NULL)
1102 return NULL;
1103 if (*needle == '\0' || *haystack == '\0')
1104 return NULL;
1105
1106#if defined(HAVE_STRSTR)
1107 return (strstr(haystack, needle));
1108#else
1109 needle_len = strlen(needle);
1110 haystack_len = strlen(haystack);
1111
1112 for (i = 0; i <= (haystack_len-needle_len); ++i)
1113 if (0 == sl_strncmp(&haystack[i], needle, needle_len))
1114 return (needle);
1115 return NULL;
1116#endif
1117}
1118
1119
1120/* ----------------------------------------------------------------
1121 *
1122 * Privilege handling routines
1123 *
1124 * ---------------------------------------------------------------- */
1125
1126
1127
1128static uid_t euid;
1129static uid_t ruid;
1130static uid_t ruid_orig;
1131static gid_t egid;
1132static gid_t rgid;
1133static gid_t rgid_orig;
1134
1135static int uids_are_stored = SL_FALSE;
1136static int suid_is_set = SL_TRUE;
1137
1138#ifdef HAVE_SETRESUID
1139extern int setresuid (uid_t truid, uid_t teuid, uid_t tsuid);
1140extern int setresgid (gid_t trgid, gid_t tegid, gid_t tsgid);
1141#endif
1142
1143
1144/*
1145 * This function returns true if the program is SUID.
1146 * It calls abort() if the uid's are not saved already.
1147 */
1148int sl_is_suid()
1149{
1150 if (uids_are_stored == SL_FALSE)
1151 {
1152 if (getuid() == geteuid() && getgid() == getegid())
1153 return (0); /* FALSE */
1154 else
1155 return (1); /* TRUE */
1156 }
1157 else
1158 {
1159 if (euid == ruid && egid == rgid)
1160 return (0); /* FALSE */
1161 else
1162 return (1); /* TRUE */
1163 }
1164}
1165
1166/*
1167 * This function returns the saved euid.
1168 * It calls abort() if the uid's are not saved already.
1169 */
1170int sl_get_euid(uid_t * ret)
1171{
1172 SL_ENTER(_("sl_get_euid"));
1173 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1174 if (uids_are_stored == SL_TRUE)
1175 *ret = euid;
1176 else
1177 *ret = geteuid();
1178 SL_IRETURN (SL_ENONE, _("sl_get_euid"));
1179}
1180
1181uid_t sl_ret_euid()
1182{
1183 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1184 if (uids_are_stored == SL_TRUE)
1185 return (euid);
1186 else
1187 return (geteuid());
1188}
1189
1190/*
1191 * This function returns the saved egid.
1192 * It calls abort() if the uid's are not saved already.
1193 */
1194int sl_get_egid(gid_t * ret)
1195{
1196 SL_ENTER(_("sl_get_egid"));
1197 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1198 if (uids_are_stored == SL_TRUE)
1199 *ret = egid;
1200 else
1201 *ret = getegid();
1202 SL_IRETURN (SL_ENONE, _("sl_get_egid"));
1203}
1204
1205/*
1206 * This function returns the saved ruid.
1207 * It calls abort() if the uid's are not saved already.
1208 */
1209int sl_get_ruid(uid_t * ret)
1210{
1211 SL_ENTER(_("sl_get_ruid"));
1212 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1213 if (uids_are_stored == SL_TRUE)
1214 *ret = ruid;
1215 else
1216 *ret = getuid();
1217 SL_IRETURN (SL_ENONE, _("sl_get_ruid"));
1218}
1219
1220/*
1221 * This function returns the saved rgid.
1222 * It calls abort() if the uid's are not saved already.
1223 */
1224int sl_get_rgid(gid_t * ret)
1225{
1226 SL_ENTER(_("sl_get_rgid"));
1227 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1228 if (uids_are_stored == SL_TRUE)
1229 *ret = rgid;
1230 else
1231 *ret = getgid();
1232 SL_IRETURN (SL_ENONE, _("sl_get_rgid"));
1233}
1234
1235/*
1236 * This function returns the saved original ruid.
1237 * It calls abort() if the uid's are not saved already.
1238 */
1239int sl_get_ruid_orig(uid_t * ret)
1240{
1241 SL_ENTER(_("sl_get_ruid_orig"));
1242 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1243 if (uids_are_stored == SL_TRUE)
1244 *ret = ruid_orig;
1245 else
1246 *ret = getuid();
1247 SL_IRETURN (SL_ENONE, _("sl_get_ruid_orig"));
1248}
1249
1250/*
1251 * This function returns the saved original rgid.
1252 * It calls abort() if the uid's are not saved already.
1253 */
1254int sl_get_rgid_orig(gid_t * ret)
1255{
1256 SL_ENTER(_("sl_get_rgid_orig"));
1257 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1258 if (uids_are_stored == SL_TRUE)
1259 *ret = rgid_orig;
1260 else
1261 *ret = getgid();
1262 SL_IRETURN (SL_ENONE, _("sl_get_rgid_orig"));
1263}
1264
1265static int suid_warn_flag = 1;
1266static void suid_warn(int a)
1267{
1268 fprintf(stderr, _("ERROR: open set/unset suid !!! %d\n"), a);
1269 return;
1270}
1271
1272/*
1273 * This function sets the effective uid
1274 * to the saved effective uid.
1275 * It will abort on failure.
1276 */
1277int sl_set_suid ()
1278{
1279 int retval;
1280
1281 SL_ENTER(_("sl_set_suid"));
1282
1283 if (uids_are_stored == SL_FALSE)
1284 {
1285 SL_IRETURN(SL_ENONE, _("sl_set_suid"));
1286 }
1287
1288 SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));
1289
1290 if (ruid == euid && rgid == egid)
1291 {
1292 suid_is_set = SL_TRUE;
1293 SL_IRETURN(SL_ENONE, _("sl_set_suid"));
1294 }
1295 SL_REQUIRE(suid_is_set == SL_FALSE, _("suid_is_set == SL_FALSE"));
1296
1297#if defined(HAVE_SETRESUID)
1298 retval = setresuid (sh_uid_neg, euid, sh_uid_neg);
1299 if (retval == 0)
1300 retval = setresgid (sh_gid_neg, egid, sh_gid_neg);
1301
1302#elif defined(HAVE_SETEUID)
1303 retval = seteuid (egid);
1304 if (retval == 0)
1305 retval = setegid (euid);
1306
1307 /* on AIX, setreuid does not behave well for non-root users.
1308 */
1309#elif defined(HAVE_SETREUID)
1310 retval = setreuid (ruid, euid);
1311 if (retval == 0)
1312 retval = setregid (rgid, egid);
1313
1314#else
1315 retval = setuid (euid);
1316 if (retval == 0)
1317 retval = setgid (egid);
1318#endif
1319 if (suid_warn_flag == 1)
1320 suid_warn(1);
1321 suid_warn_flag = 1;
1322
1323 SL_REQUIRE(retval == 0, _("retval == 0"));
1324 suid_is_set = SL_TRUE;
1325 SL_IRETURN(SL_ENONE, _("sl_set_suid"));
1326}
1327
1328/*
1329 * This function sets the effective uid to the real uid.
1330 * It will abort on failure.
1331 */
1332int sl_unset_suid ()
1333{
1334 register int retval;
1335
1336 SL_ENTER(_("sl_unset_suid"));
1337
1338 if (uids_are_stored == SL_FALSE)
1339 {
1340 SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
1341 }
1342
1343 SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));
1344
1345 if (ruid == euid && rgid == egid)
1346 {
1347 suid_is_set = SL_FALSE;
1348 SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
1349 }
1350 SL_REQUIRE(suid_is_set == SL_TRUE, _("suid_is_set == SL_TRUE"));
1351
1352#if defined(HAVE_SETRESUID)
1353 retval = setresgid (sh_gid_neg, rgid, sh_gid_neg);
1354 if (retval == 0)
1355 retval = setresuid (sh_uid_neg, ruid, sh_uid_neg);
1356
1357#elif defined(HAVE_SETEUID)
1358 retval = setegid (rgid);
1359 if (retval == 0)
1360 retval = seteuid (ruid);
1361
1362#elif defined(HAVE_SETREUID)
1363 retval = setregid (egid, rgid);
1364 if (retval == 0)
1365 retval = setreuid (euid, ruid);
1366
1367#else
1368 retval = setgid (rgid);
1369 if (retval == 0)
1370 retval = setuid (ruid);
1371#endif
1372
1373 if (suid_warn_flag == 0)
1374 suid_warn(0);
1375 suid_warn_flag = 0;
1376
1377 SL_REQUIRE(retval == 0, _("retval == 0"));
1378 suid_is_set = SL_FALSE;
1379 SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
1380}
1381
1382
1383/*
1384 * This function saves the uid's.
1385 */
1386int sl_save_uids()
1387{
1388 SL_ENTER(_("sl_save_uids"));
1389 if (uids_are_stored == SL_TRUE)
1390 SL_IRETURN(SL_EREPEAT, _("sl_save_uids"));
1391
1392 ruid_orig = getuid();
1393 rgid_orig = getgid();
1394 egid = getegid();
1395 euid = geteuid();
1396 ruid = ruid_orig;
1397 rgid = rgid_orig;
1398 uids_are_stored = SL_TRUE;
1399
1400 SL_IRETURN(SL_ENONE, _("sl_save_uids"));
1401}
1402
1403/*
1404 * This function drops SUID privileges irrevocably.
1405 * It set the effective uid to the original real uid.
1406 */
1407extern int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid);
1408int sl_drop_privileges()
1409{
1410 SL_ENTER(_("sl_drop_privileges"));
1411 SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));
1412
1413 SL_REQUIRE(setgid(rgid_orig) == 0, _("setgid(rgid_orig) == 0"));
1414 SL_REQUIRE(sh_unix_initgroups2(ruid_orig, rgid_orig) == 0, _("sh_unix_initgroups2(ruid_orig,rgid_orig) == 0"));
1415 SL_REQUIRE(setuid(ruid_orig) == 0, _("setuid(ruid_orig) == 0"));
1416
1417 /* make sure that setuid(0) fails
1418 */
1419 SL_REQUIRE(setuid(0) < 0, _("setuid(0) < 0"));
1420
1421 euid = ruid_orig;
1422 egid = rgid_orig;
1423 ruid = ruid_orig;
1424 rgid = rgid_orig;
1425
1426 SL_IRETURN(SL_ENONE, _("sl_drop_privileges"));
1427}
1428
1429/*
1430 * Define a policy: Stay root.
1431 * Do nothing if not SUID.
1432 */
1433int sl_policy_get_root()
1434{
1435 SL_ENTER(_("sl_policy_get_root"));
1436 SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1437
1438 SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1439
1440 if (euid != ruid || egid != rgid)
1441 {
1442 SL_REQUIRE(setgid(egid) == 0, _("setgid(egid) == 0"));
1443 SL_REQUIRE(setuid(euid) == 0, _("setuid(euid) == 0"));
1444 SL_REQUIRE(ruid == getuid() && rgid == getgid(),
1445 _("ruid == getuid() && rgid == getgid()"));
1446 ruid = euid;
1447 rgid = egid;
1448 }
1449 suid_is_set = SL_TRUE;
1450 if (euid == 0)
1451 {
1452 SL_REQUIRE(sh_unix_initgroups2(euid, egid) == 0, _("sh_unix_initgroups2(euid,egid) == 0"));
1453 }
1454 SL_IRETURN(SL_ENONE, _("sl_policy_get_root"));
1455}
1456
1457#include <pwd.h>
1458
1459/*
1460 * Define a policy: Get real (irrevocably).
1461 * This function drops SUID privileges irrevocably.
1462 * Do nothing if not SUID (? not true - drops if root).
1463 */
1464
1465int sl_policy_get_real(char * user)
1466{
1467 SL_ENTER(_("sl_policy_get_real"));
1468 SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1469 SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1470
1471 if (euid == 0 || ruid == 0)
1472 {
1473#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1474 struct passwd pwd;
1475 char * buffer;
1476 struct passwd * tempres;
1477 buffer = malloc(SH_PWBUF_SIZE);
1478 SL_REQUIRE (buffer != NULL, _("buffer != NULL"));
1479 sh_getpwnam_r(user, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
1480#else
1481 struct passwd * tempres = sh_getpwnam(user);
1482#endif
1483
1484 SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1485
1486 rgid_orig = tempres->pw_gid;
1487 ruid_orig = tempres->pw_uid;
1488#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1489 free(buffer);
1490#endif
1491 }
1492 else
1493 {
1494 rgid_orig = rgid;
1495 ruid_orig = ruid;
1496 }
1497
1498 SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1499 _("sl_drop_privileges() == SL_ENONE"));
1500
1501 suid_is_set = SL_TRUE;
1502 SL_IRETURN(SL_ENONE, _("sl_policy_get_real"));
1503}
1504
1505
1506/*
1507 * Define a policy: Get user.
1508 * Drops privileges.
1509 * Do nothing if not SUID.
1510 */
1511int sl_policy_get_user(const char * user)
1512{
1513 SL_ENTER(_("sl_policy_get_user"));
1514
1515 SL_REQUIRE(user != NULL, _("user != NULL"));
1516 SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1517 SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1518
1519 if (euid != ruid || egid != rgid)
1520 {
1521#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1522 struct passwd pwd;
1523 char * buffer;
1524 struct passwd * tempres;
1525 buffer = malloc(SH_PWBUF_SIZE);
1526 SL_REQUIRE (buffer != NULL, _("buffer != NULL"));
1527 sh_getpwnam_r(user, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
1528#else
1529 struct passwd * tempres = sh_getpwnam(user);
1530#endif
1531
1532 SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1533
1534 SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1535 _("sl_drop_privileges() == SL_ENONE"));
1536#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1537 free(buffer);
1538#endif
1539 }
1540 SL_IRETURN(SL_ENONE, _("sl_policy_get_user"));
1541}
1542
1543
1544
1545/* ----------------------------------------------------------------
1546 *
1547 * File access routines
1548 *
1549 * ---------------------------------------------------------------- */
1550
1551#define TOFFSET 0x1234
1552
1553/* this would prevent opening files if the first 16 fds are open :( */
1554/* #define MAXFD FOPEN_MAX */
1555
1556#define MAXFD 1024
1557
1558typedef struct openfiles {
1559 SL_TICKET ticket; /* The unique ID. */
1560 int fd; /* The file descriptor. */
1561 FILE * stream; /* The file descriptor. */
1562 char * path; /* The file path. */
1563 int flush; /* Whether we want to flush the cache */
1564 char ofile[SL_OFILE_SIZE]; /* origin file */
1565 int oline; /* origin line */
1566 sh_string * content; /* The file content */
1567} SL_OFILE;
1568
1569static SL_OFILE * ofiles[MAXFD];
1570
1571static char stale_orig_file[64] = { '\0' };
1572static int stale_orig_line = -1;
1573static char stale_orig_mesg[128];
1574
1575static char badfd_orig_file[64] = { '\0' };
1576static int badfd_orig_line = -1;
1577static char badfd_orig_mesg[128];
1578
1579SH_MUTEX_STATIC(mutex_ticket, PTHREAD_MUTEX_INITIALIZER);
1580
1581static unsigned int nonce_counter = TOFFSET;
1582
1583char * sl_check_stale()
1584{
1585 if (stale_orig_line == -1)
1586 return NULL;
1587 sl_snprintf(stale_orig_mesg, sizeof(stale_orig_mesg),
1588 _("stale handle, %s, %d"), stale_orig_file, stale_orig_line);
1589 stale_orig_file[0] = '\0';
1590 stale_orig_line = -1;
1591 return stale_orig_mesg;
1592}
1593
1594char * sl_check_badfd()
1595{
1596 if (badfd_orig_line == -1)
1597 return NULL;
1598 sl_snprintf(badfd_orig_mesg, sizeof(badfd_orig_mesg),
1599 _("close on file descriptor with allocated handle, %s, %d"),
1600 badfd_orig_file, badfd_orig_line);
1601 badfd_orig_file[0] = '\0';
1602 badfd_orig_line = -1;
1603 return badfd_orig_mesg;
1604}
1605
1606static
1607SL_TICKET sl_create_ticket (unsigned int myindex)
1608{
1609 unsigned int high; /* index */
1610 unsigned int low; /* nonce */
1611 SL_TICKET retval = SL_EINTERNAL;
1612
1613 SL_ENTER(_("sl_create_ticket"));
1614
1615 if (myindex >= MAXFD)
1616 {
1617 retval = SL_EINTERNAL01;
1618 goto out_ticket;
1619 }
1620
1621 /* mask out the high bit and check that it is not used
1622 * -> verify that it fits into 16 bits as positive
1623 */
1624 high = (myindex + TOFFSET) & 0x7fff;
1625
1626 if (high != myindex + TOFFSET)
1627 {
1628 retval = SL_EINTERNAL02;
1629 goto out_ticket;
1630 }
1631
1632 SH_MUTEX_LOCK_UNSAFE(mutex_ticket);
1633
1634 low = nonce_counter & 0xffff;
1635
1636 /* Overflow -> nonce too big.
1637 */
1638 if ((low != nonce_counter++) || low == 0)
1639 {
1640 retval = SL_EINTERNAL03;
1641 goto out_ticket;
1642 }
1643
1644 /* Wrap around the nonce counter.
1645 * This is a dirty trick.
1646 */
1647 if (nonce_counter > 0x7fff)
1648 nonce_counter = TOFFSET;
1649
1650 retval = (SL_TICKET) ((high << 16) | low);
1651
1652 out_ticket:
1653 ;
1654
1655 SH_MUTEX_UNLOCK_UNSAFE(mutex_ticket);
1656 SL_RETURN (retval, _("sl_create_ticket"));
1657}
1658
1659static
1660int sl_read_ticket (SL_TICKET fno)
1661{
1662 register unsigned myindex;
1663 register SL_OFILE *of;
1664
1665 myindex = ((fno >> 16) & 0xffff) - TOFFSET;
1666 if (myindex >= MAXFD)
1667 return (SL_ETICKET);
1668
1669 if (ofiles[myindex] == NULL)
1670 return (SL_ETICKET);
1671
1672 if (ofiles[myindex]->ticket != fno)
1673 return (SL_ETICKET);
1674
1675 if ((of = ofiles[myindex])->fd < 0 || of->fd >= MAXFD )
1676 return (SL_EINTERNAL04);
1677
1678 if (((of->ticket) & 0xffff) == 0)
1679 return (SL_EINTERNAL05);
1680
1681 return (myindex);
1682}
1683
1684SL_TICKET sl_make_ticket (const char * ofile, int oline,
1685 int fd, const char * filename, FILE * stream)
1686{
1687 size_t len;
1688 SL_TICKET ticket;
1689 SL_ENTER(_("sl_make_ticket"));
1690 /* Make entry.
1691 */
1692 if (fd >= MAXFD || fd < 0)
1693 {
1694 SL_IRETURN(SL_TOOMANY, _("sl_make_ticket"));
1695 }
1696
1697 if (ofiles[fd] != NULL) /* stale entry */
1698 {
1699 /* SL_IRETURN(SL_EINTERNAL06, _("sl_make_ticket")); */
1700 sl_strlcpy(stale_orig_file, ofiles[fd]->ofile, sizeof(stale_orig_file));
1701 stale_orig_line = ofiles[fd]->oline;
1702
1703 if (ofiles[fd]->content)
1704 sh_string_destroy(&(ofiles[fd]->content));
1705 (void) free (ofiles[fd]->path);
1706 (void) free (ofiles[fd]);
1707 ofiles[fd] = NULL;
1708 }
1709
1710 if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1711 {
1712 SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1713 }
1714
1715 len = sl_strlen(filename)+1;
1716
1717 if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
1718 {
1719 free (ofiles[fd]);
1720 ofiles[fd] = NULL;
1721 SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1722 }
1723
1724 /* Get a ticket.
1725 */
1726 ticket = sl_create_ticket((unsigned int)fd);
1727
1728 if (SL_ISERROR(ticket))
1729 {
1730 (void) free (ofiles[fd]->path);
1731 (void) free (ofiles[fd]);
1732 ofiles[fd] = NULL;
1733 SL_IRETURN(ticket, _("sl_make_ticket"));
1734 }
1735
1736 sl_strlcpy (ofiles[fd]->path, filename, len);
1737 ofiles[fd]->ticket = ticket;
1738 ofiles[fd]->fd = fd;
1739 ofiles[fd]->content = NULL;
1740 ofiles[fd]->stream = stream;
1741 ofiles[fd]->flush = SL_FALSE;
1742
1743 sl_strlcpy(ofiles[fd]->ofile, ofile, SL_OFILE_SIZE);
1744 ofiles[fd]->oline = oline;
1745
1746 SL_IRETURN(ticket, _("sl_make_ticket"));
1747}
1748
1749#define SL_OPEN_MIN 113
1750#define SL_OPEN_FOR_READ 113
1751#define SL_OPEN_FOR_WRITE 114
1752#define SL_OPEN_FOR_RDWR 115
1753#define SL_OPEN_FOR_WTRUNC 116
1754#define SL_OPEN_FOR_RWTRUNC 117
1755#define SL_OPEN_SAFE_RDWR 118
1756#define SL_OPEN_FOR_FASTREAD 119
1757#define SL_OPEN_MAX 119
1758
1759#if !defined(O_NOATIME)
1760#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
1761#define O_NOATIME 01000000
1762#else
1763 /*
1764 * bitwise 'or' with zero does not modify any bit
1765 */
1766#define O_NOATIME 0
1767#endif
1768#endif
1769
1770static int o_noatime = O_NOATIME;
1771static mode_t open_mode = (S_IWUSR|S_IRUSR|S_IRGRP);
1772
1773
1774static
1775int sl_open_file (const char * ofile, int oline,
1776 const char *filename, int mode, int priv)
1777{
1778 struct stat lbuf;
1779 struct stat buf;
1780 int errval = 0;
1781 int lstat_return;
1782 int stat_return;
1783 int fd;
1784 int sflags;
1785 size_t len;
1786 SL_TICKET ticket;
1787
1788#if !defined(O_NONBLOCK)
1789#if defined(O_NDELAY)
1790#define O_NONBLOCK O_NDELAY
1791#else
1792#define O_NONBLOCK 0
1793#endif
1794#endif
1795
1796 SL_ENTER(_("sl_open_file"));
1797
1798 if (filename == NULL)
1799 SL_IRETURN(SL_ENULL, _("sl_open_file"));
1800 if (mode < SL_OPEN_MIN || mode > SL_OPEN_MAX)
1801 SL_IRETURN(SL_EINTERNAL07, _("sl_open_file"));
1802
1803 /* "This system call always succeeds and the previous value of
1804 * the mask is returned."
1805 */
1806 (void) umask (0);
1807
1808 if (mode == SL_OPEN_FOR_FASTREAD)
1809 {
1810 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1811 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
1812 /*
1813 if (fd >= 0) {
1814 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1815 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1816 }
1817 */
1818 if (fd < 0)
1819 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1820 goto createTicket;
1821 }
1822
1823#ifdef USE_SUID
1824 if (priv == SL_YESPRIV)
1825 sl_set_suid();
1826#endif
1827 if (mode == SL_OPEN_FOR_READ)
1828 lstat_return = retry_stat (FIL__, __LINE__, filename, &lbuf);
1829 else
1830 lstat_return = retry_lstat(FIL__, __LINE__, filename, &lbuf);
1831 errval = errno;
1832#ifdef USE_SUID
1833 if (priv == SL_YESPRIV)
1834 sl_unset_suid();
1835#endif
1836
1837 if (lstat_return == -1)
1838 {
1839 lstat_return = ENOENT;
1840 if ( (mode == SL_OPEN_FOR_READ && lstat_return == ENOENT) ||
1841 (errval != ENOENT))
1842 {
1843 TPT(( 0, FIL__, __LINE__, _("msg=<lstat: %s> errno=<%d>\n"),
1844 filename, errval));
1845 errno = errval;
1846 SL_IRETURN(SL_ESTAT, _("sl_open_file"));
1847 }
1848 }
1849
1850 if ( (mode != SL_OPEN_FOR_READ) && (lstat_return != ENOENT) &&
1851 ( S_ISDIR(lbuf.st_mode) || (S_IWOTH & lbuf.st_mode) )
1852 )
1853 {
1854 int retval = S_ISDIR(lbuf.st_mode) ? SL_EISDIR : SL_EBADOTH;
1855 errno = 0;
1856 SL_IRETURN(retval, _("sl_open_file"));
1857 }
1858
1859 /* O_NOATIME has an effect for read(). But write() ?.
1860 */
1861 switch (mode)
1862 {
1863 case SL_OPEN_FOR_READ:
1864 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1865 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
1866 errval = errno;
1867 if (fd >= 0) {
1868 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1869 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1870 }
1871 break;
1872 case SL_OPEN_FOR_WRITE:
1873 if (lstat_return == ENOENT)
1874 fd = aud_open (FIL__, __LINE__, priv, filename,
1875 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1876 else
1877 fd = aud_open (FIL__, __LINE__, priv, filename,
1878 O_WRONLY, open_mode);
1879 errval = errno;
1880 break;
1881 case SL_OPEN_SAFE_RDWR:
1882 if (lstat_return == ENOENT)
1883 {
1884 fd = aud_open (FIL__, __LINE__, priv, filename,
1885 O_RDWR|O_CREAT|O_EXCL, open_mode);
1886 errval = errno;
1887 }
1888 else
1889 {
1890 errno = errval;
1891 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1892 }
1893 break;
1894 case SL_OPEN_FOR_RDWR:
1895 if (lstat_return == ENOENT)
1896 fd = aud_open (FIL__, __LINE__, priv, filename,
1897 O_RDWR|O_CREAT|O_EXCL, open_mode);
1898 else
1899 fd = aud_open (FIL__, __LINE__, priv, filename,
1900 O_RDWR, open_mode);
1901 errval = errno;
1902 break;
1903 case SL_OPEN_FOR_WTRUNC:
1904 if (lstat_return == ENOENT)
1905 fd = aud_open (FIL__, __LINE__, priv, filename,
1906 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1907 else
1908 fd = aud_open (FIL__, __LINE__, priv, filename,
1909 O_WRONLY|O_TRUNC, open_mode);
1910 errval = errno;
1911 break;
1912 case SL_OPEN_FOR_RWTRUNC:
1913 if (lstat_return == ENOENT)
1914 fd = aud_open (FIL__, __LINE__, priv, filename,
1915 O_RDWR|O_CREAT|O_EXCL, open_mode);
1916 else
1917 fd = aud_open (FIL__, __LINE__, priv, filename,
1918 O_RDWR|O_TRUNC, open_mode);
1919 errval = errno;
1920 break;
1921 default:
1922 errno = 0;
1923 SL_IRETURN(SL_EINTERNAL08, _("sl_open_file"));
1924 }
1925
1926 if (fd < 0)
1927 {
1928 TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s> errno=<%d>\n"),
1929 filename, errval));
1930 errno = errval;
1931 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1932 }
1933
1934#ifdef USE_SUID
1935 if (priv == SL_YESPRIV)
1936 sl_set_suid();
1937#endif
1938 stat_return = retry_fstat(FIL__, __LINE__, fd, &buf);
1939 errval = errno;
1940#ifdef USE_SUID
1941 if (priv == SL_YESPRIV)
1942 sl_unset_suid();
1943#endif
1944
1945 if (stat_return < 0)
1946 {
1947 sl_close_fd (FIL__, __LINE__, fd);
1948 errno = errval;
1949 SL_IRETURN(SL_EFSTAT, _("sl_open_file"));
1950 }
1951
1952 errno = 0;
1953
1954 if (lstat_return != ENOENT && buf.st_ino != lbuf.st_ino)
1955 {
1956 sl_close_fd (FIL__, __LINE__, fd);
1957 SL_IRETURN(SL_EBOGUS, _("sl_open_file"));
1958 }
1959
1960 createTicket:
1961
1962 /* Make entry.
1963 */
1964 if (fd >= MAXFD)
1965 {
1966 sl_close_fd(FIL__, __LINE__, fd);
1967 SL_IRETURN(SL_TOOMANY, _("sl_open_file"));
1968 }
1969
1970 if (ofiles[fd] != NULL) /* stale entry */
1971 {
1972 /*
1973 sl_close_fd(FIL__, __LINE__, fd);
1974 SL_IRETURN(SL_EINTERNAL09, _("sl_open_file"));
1975 */
1976 sl_strlcpy(stale_orig_file, ofiles[fd]->ofile, sizeof(stale_orig_file));
1977 stale_orig_line = ofiles[fd]->oline;
1978
1979 if (ofiles[fd]->content)
1980 sh_string_destroy(&(ofiles[fd]->content));
1981 (void) free (ofiles[fd]->path);
1982 (void) free (ofiles[fd]);
1983 ofiles[fd] = NULL;
1984 }
1985
1986 if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1987 {
1988 sl_close_fd(FIL__, __LINE__, fd);
1989 SL_IRETURN(SL_EMEM, _("sl_open_file"));
1990 }
1991
1992 len = sl_strlen(filename)+1;
1993
1994 if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
1995 {
1996 free (ofiles[fd]);
1997 ofiles[fd] = NULL;
1998 sl_close_fd(FIL__, __LINE__, fd);
1999 SL_IRETURN(SL_EMEM, _("sl_open_file"));
2000 }
2001
2002 /* Get a ticket.
2003 */
2004 ticket = sl_create_ticket(fd);
2005
2006 if (SL_ISERROR(ticket))
2007 {
2008 (void) free (ofiles[fd]->path);
2009 (void) free (ofiles[fd]);
2010 ofiles[fd] = NULL;
2011 sl_close_fd(FIL__, __LINE__, fd);
2012 SL_IRETURN(ticket, _("sl_open_file"));
2013 }
2014
2015 sl_strlcpy (ofiles[fd]->path, filename, len);
2016 ofiles[fd]->ticket = ticket;
2017 ofiles[fd]->fd = fd;
2018 ofiles[fd]->content = NULL;
2019 ofiles[fd]->stream = NULL;
2020 ofiles[fd]->flush = SL_FALSE;
2021
2022 sl_strlcpy(ofiles[fd]->ofile, ofile, SL_OFILE_SIZE);
2023 ofiles[fd]->oline = oline;
2024
2025 SL_IRETURN(ticket, _("sl_open_file"));
2026}
2027
2028FILE * sl_stream (SL_TICKET ticket, char * mode)
2029{
2030 int fd;
2031
2032 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2033 return (NULL);
2034
2035 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
2036 ticket != ofiles[fd]->ticket || fd < 0)
2037 return (NULL);
2038
2039 if (!ofiles[fd]->stream)
2040 ofiles[fd]->stream = fdopen(fd, mode);
2041
2042 return ofiles[fd]->stream;
2043}
2044
2045int get_the_fd (SL_TICKET ticket)
2046{
2047 int fd;
2048
2049 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2050 return (fd);
2051
2052 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
2053 ticket != ofiles[fd]->ticket || fd < 0)
2054 return (SL_EINTERNAL10);
2055
2056 return (fd);
2057}
2058
2059static
2060int check_fname_priv (const char * fname, int priv)
2061{
2062 SL_ENTER(_("check_fname_priv"));
2063 if (fname == NULL)
2064 SL_IRETURN(SL_ENULL, _("check_fname_priv"));
2065 if (priv != SL_YESPRIV && priv != SL_NOPRIV)
2066 SL_IRETURN(SL_EINTERNAL11, _("check_fname_priv"));
2067 SL_IRETURN(SL_ENONE, _("check_fname_priv"));
2068}
2069
2070SL_TICKET sl_open_write (const char * ofile, int oline,
2071 const char * fname, int priv)
2072{
2073 long status;
2074 SL_ENTER(_("sl_open_write"));
2075
2076 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2077 SL_IRETURN(status, _("sl_open_write"));
2078
2079 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_WRITE, priv);
2080 SL_IRETURN(status, _("sl_open_write"));
2081}
2082
2083SL_TICKET sl_open_read (const char * ofile, int oline,
2084 const char * fname, int priv)
2085{
2086 long status;
2087 SL_ENTER(_("sl_open_read"));
2088
2089 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2090 {
2091 TPT(( 0, FIL__, __LINE__,
2092 _("msg=<Error in check_fname_priv.> status=<%ld>\n"),
2093 status));
2094 SL_IRETURN(status, _("sl_open_read"));
2095 }
2096
2097 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_READ, priv);
2098 SL_IRETURN(status, _("sl_open_read"));
2099}
2100
2101#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
2102static int sl_check_mincore(int fd)
2103{
2104 /* Idea from Tobias Oetiker (http://insights.oetiker.ch/linux/fadvise.html)
2105 */
2106 struct stat fbuf;
2107 int retval = -1;
2108
2109 if (0 == fstat(fd, &fbuf))
2110 {
2111 void *f_map;
2112
2113 f_map = mmap((void *)0, fbuf.st_size, PROT_NONE, MAP_SHARED, fd, 0);
2114 if (MAP_FAILED != f_map)
2115 {
2116 extern int sh_unix_pagesize(void);
2117 size_t i;
2118 size_t page_size = sh_unix_pagesize();
2119 size_t vec_size = (fbuf.st_size+page_size-1)/page_size;
2120 unsigned char * vec = calloc(1, vec_size);
2121
2122 if (vec)
2123 {
2124 mincore(f_map, fbuf.st_size, vec);
2125 /* imax = fbuf.st_size/page_size; */
2126 for (i = 0; i <= vec_size; ++i)
2127 {
2128 if (vec[i]&1)
2129 {
2130 goto incore;
2131 }
2132 }
2133 retval = 0;
2134 incore:
2135 free(vec);
2136 }
2137 munmap(f_map, fbuf.st_size);
2138 }
2139 }
2140 return retval;
2141}
2142#endif
2143
2144static int sl_drop_cache = SL_FALSE;
2145
2146int sl_set_drop_cache(const char * str)
2147{
2148 extern int sh_util_flagval(const char * c, int * fval);
2149 return sh_util_flagval(str, &sl_drop_cache);
2150}
2151
2152SL_TICKET sl_open_fastread (const char * ofile, int oline,
2153 const char * fname, int priv)
2154{
2155 long status;
2156 SL_ENTER(_("sl_open_fastread"));
2157
2158 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2159 SL_IRETURN(status, _("sl_open_read"));
2160
2161 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_FASTREAD, priv);
2162
2163#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
2164
2165 if (SL_FALSE != sl_drop_cache && !SL_ISERROR(status))
2166 {
2167 int fd = get_the_fd(status);
2168 if (fd >= 0)
2169 {
2170 if (0 == sl_check_mincore(fd))
2171 ofiles[fd]->flush = SL_TRUE;
2172 }
2173 }
2174
2175#endif
2176
2177 SL_IRETURN(status, _("sl_open_fastread"));
2178}
2179
2180SL_TICKET sl_open_rdwr (const char * ofile, int oline,
2181 const char * fname, int priv)
2182{
2183 long status;
2184 SL_ENTER(_("sl_open_rdwr"));
2185
2186 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2187 SL_IRETURN(status, _("sl_open_rdwr"));
2188
2189 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_RDWR, priv);
2190 SL_IRETURN(status, _("sl_open_rdwr"));
2191}
2192
2193SL_TICKET sl_open_safe_rdwr (const char * ofile, int oline,
2194 const char * fname, int priv)
2195{
2196 long status;
2197 SL_ENTER(_("sl_open_safe_rdwr"));
2198
2199 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2200 SL_IRETURN(status, _("sl_open_safe_rdwr"));
2201
2202 status = sl_open_file(ofile, oline, fname, SL_OPEN_SAFE_RDWR, priv);
2203 SL_IRETURN(status, _("sl_open_safe_rdwr"));
2204}
2205
2206SL_TICKET sl_open_write_trunc (const char * ofile, int oline,
2207 const char * fname, int priv)
2208{
2209 long status;
2210 SL_ENTER(_("sl_open_write_trunc"));
2211
2212 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2213 SL_IRETURN(status, _("sl_open_write_trunc"));
2214
2215 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_WTRUNC, priv);
2216 SL_IRETURN(status, _("sl_open_write_trunc"));
2217}
2218
2219SL_TICKET sl_open_rdwr_trunc (const char * ofile, int oline,
2220 const char * fname, int priv)
2221{
2222 long status;
2223 SL_ENTER(_("sl_open_rdwr_trunc"));
2224
2225 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2226 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
2227
2228 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_RWTRUNC, priv);
2229 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
2230}
2231
2232
2233int sl_init_content (SL_TICKET ticket, size_t size)
2234{
2235 int fd;
2236
2237 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2238 return (fd);
2239
2240 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
2241 ticket != ofiles[fd]->ticket || fd < 0)
2242 return (SL_EINTERNAL12);
2243
2244 if (ofiles[fd]->content)
2245 sh_string_destroy(&(ofiles[fd]->content));
2246 ofiles[fd]->content = sh_string_new(size);
2247
2248 return SL_ENONE;
2249}
2250
2251sh_string * sl_get_content (SL_TICKET ticket)
2252{
2253 int fd;
2254
2255 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2256 return (NULL);
2257
2258 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
2259 ticket != ofiles[fd]->ticket || fd < 0)
2260 return (NULL);
2261
2262 return (ofiles[fd]->content);
2263}
2264
2265int sl_lock (SL_TICKET ticket)
2266{
2267 int fd;
2268 struct flock lock;
2269 int retval;
2270
2271 SL_ENTER(_("sl_lock"));
2272
2273 if (SL_ISERROR(fd = get_the_fd (ticket)))
2274 SL_IRETURN(fd, _("sl_lock"));
2275
2276 lock.l_type = F_WRLCK;
2277 lock.l_whence = SEEK_SET;
2278 lock.l_start = 0;
2279 lock.l_len = 0;
2280
2281 /* F_SETLK returns if the lock cannot be obtained */
2282 do {
2283 retval = fcntl(fd, F_SETLK, &lock);
2284 } while (retval < 0 && errno == EINTR);
2285
2286 if (retval < 0 && errno == EBADF)
2287 SL_IRETURN(SL_ETICKET, _("sl_lock"));
2288 else if (retval < 0)
2289 SL_IRETURN(SL_EBADFILE, _("sl_lock"));
2290 else
2291 SL_IRETURN(SL_ENONE, _("sl_lock"));
2292 }
2293
2294int sl_close (SL_TICKET ticket)
2295{
2296 register int fd;
2297 FILE * fp = NULL;
2298
2299 SL_ENTER(_("sl_close"));
2300
2301 if (SL_ISERROR(fd = get_the_fd (ticket)))
2302 SL_IRETURN(fd, _("sl_close"));
2303
2304 if (ofiles[fd] != NULL)
2305 {
2306#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
2307 if (ofiles[fd]->flush == SL_TRUE)
2308 {
2309 posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
2310 }
2311#endif
2312 if (ofiles[fd]->content)
2313 sh_string_destroy(&(ofiles[fd]->content));
2314 (void) free (ofiles[fd]->path);
2315 fp = ofiles[fd]->stream;
2316 (void) free (ofiles[fd]);
2317 ofiles[fd] = NULL;
2318 }
2319
2320 /* This may fail, but what to do then ?
2321 */
2322 if (fp)
2323 {
2324 if (0 != fclose (fp)) /* within sl_close */
2325 {
2326 TPT((0, FIL__, __LINE__,
2327 _("msg=<Error fclosing file.>, fd=<%d>, err=<%s>\n"),
2328 fd, strerror(errno)));
2329 }
2330 }
2331 else
2332 {
2333 if (0 != close(fd)) /* within sl_close */
2334 {
2335 TPT((0, FIL__, __LINE__,
2336 _("msg=<Error closing file.>, fd=<%d>, err=<%s>\n"),
2337 fd, strerror(errno)));
2338 }
2339 }
2340
2341 SL_IRETURN(SL_ENONE, _("sl_close"));
2342}
2343
2344int sl_close_fd (const char * file, int line, int fd)
2345{
2346 int ret = -1;
2347
2348 SL_ENTER(_("sl_close_fd"));
2349
2350 if (fd >= 0 && fd < MAXFD && ofiles[fd] != NULL) /* stale ofiles[fd] handle */
2351 {
2352 sl_strlcpy(badfd_orig_file, file, sizeof(badfd_orig_file));
2353 badfd_orig_line = line;
2354 }
2355
2356 ret = close(fd); /* within sl_close_fd wrapper */
2357
2358 SL_IRETURN(ret, _("sl_close_fd"));
2359}
2360
2361int sl_fclose (const char * file, int line, FILE * fp)
2362{
2363 int ret = -1;
2364 int fd;
2365
2366 SL_ENTER(_("sl_fclose"));
2367
2368 fd = fileno(fp);
2369
2370 if (fd >= 0 && fd < MAXFD && ofiles[fd] != NULL) /* stale ofiles[fd] handle */
2371 {
2372 sl_strlcpy(badfd_orig_file, file, sizeof(badfd_orig_file));
2373 badfd_orig_line = line;
2374 }
2375
2376 ret = fclose(fp); /* within sl_fclose wrapper */
2377
2378 SL_IRETURN(ret, _("sl_fclose"));
2379}
2380
2381int sl_dropall(int fd, int except)
2382{
2383 while (fd < MAXFD)
2384 {
2385 if (ofiles[fd] != NULL && fd != except)
2386 {
2387 if (ofiles[fd]->content)
2388 sh_string_destroy(&(ofiles[fd]->content));
2389 if (ofiles[fd]->path != NULL)
2390 (void) free (ofiles[fd]->path);
2391 (void) free (ofiles[fd]);
2392 ofiles[fd] = NULL;
2393 }
2394 ++fd;
2395 }
2396 return 0;
2397}
2398
2399int sl_dropall_dirty(int fd, int except)
2400{
2401 while (fd < MAXFD)
2402 {
2403 if (ofiles[fd] != NULL && fd != except)
2404 {
2405 ofiles[fd] = NULL;
2406 }
2407 ++fd;
2408 }
2409 return 0;
2410}
2411
2412
2413int sl_unlink (SL_TICKET ticket)
2414{
2415 register int fd;
2416
2417 SL_ENTER(_("sl_unlink"));
2418
2419 if (SL_ISERROR(fd = get_the_fd(ticket)))
2420 SL_IRETURN(fd, _("sl_unlink"));
2421
2422 if (retry_aud_unlink(FIL__, __LINE__, ofiles[fd]->path) < 0)
2423 SL_IRETURN(SL_EUNLINK, _("sl_unlink"));
2424
2425 SL_IRETURN(SL_ENONE, _("sl_unlink"));
2426}
2427
2428
2429int sl_seek (SL_TICKET ticket, off_t off_data)
2430{
2431 register int fd;
2432
2433 SL_ENTER(_("sl_seek"));
2434
2435 if (SL_ISERROR(fd = get_the_fd(ticket)))
2436 SL_IRETURN(fd, _("sl_seek"));
2437
2438 if (lseek(fd, off_data, SEEK_SET) == (off_t)-1)
2439 SL_IRETURN(SL_EREWIND, _("sl_seek"));
2440
2441 SL_IRETURN(SL_ENONE, _("sl_seek"));
2442}
2443
2444int sl_rewind (SL_TICKET ticket)
2445{
2446 register int fd;
2447
2448 SL_ENTER(_("sl_rewind"));
2449
2450 if (SL_ISERROR(fd = get_the_fd(ticket)))
2451 SL_IRETURN(fd, _("sl_rewind"));
2452
2453 if (lseek (fd, 0L, SEEK_SET) == (off_t)-1)
2454 SL_IRETURN(SL_EREWIND, _("sl_rewind"));
2455
2456 SL_IRETURN(SL_ENONE, _("sl_rewind"));
2457}
2458
2459int sl_forward (SL_TICKET ticket)
2460{
2461 register int fd;
2462
2463 SL_ENTER(_("sl_forward"));
2464
2465 if (SL_ISERROR(fd = get_the_fd(ticket)))
2466 SL_IRETURN(fd, _("sl_forward"));
2467
2468 if (lseek (fd, 0L, SEEK_END) == (off_t)-1)
2469 SL_IRETURN(SL_EFORWARD, _("sl_forward"));
2470
2471 SL_IRETURN(SL_ENONE, _("sl_forward"));
2472}
2473
2474
2475int sl_sync (SL_TICKET ticket)
2476{
2477 register int fd;
2478
2479 SL_ENTER(_("sl_sync"));
2480
2481 if (SL_ISERROR(fd = get_the_fd(ticket)))
2482 SL_IRETURN(fd, _("sl_sync"));
2483
2484 if (fsync (fd) == -1)
2485 SL_IRETURN(SL_ESYNC, _("sl_sync"));
2486
2487 SL_IRETURN(SL_ENONE, _("sl_sync"));
2488}
2489
2490int sl_read_timeout_prep (SL_TICKET ticket)
2491{
2492 int fd;
2493 int sflags;
2494
2495 SL_ENTER(_("sl_read_timeout_prep"));
2496
2497 if (SL_ISERROR(fd = get_the_fd(ticket)))
2498 {
2499 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2500 SL_IRETURN(fd, _("sl_read_timeout_prep"));
2501 }
2502
2503 /* set to non-blocking mode
2504 */
2505 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2506 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
2507
2508 SL_IRETURN(SL_ENONE, _("sl_read_timeout_prep"));
2509}
2510
2511
2512int sl_read_timeout_fd (int fd, void * buf_in, size_t count,
2513 int timeout, int is_nonblocking)
2514{
2515 int sflags = 0;
2516 fd_set readfds;
2517 struct timeval tv;
2518 /* int sflags; */
2519 int retval;
2520 int error;
2521
2522 int byteread = 0;
2523 int bytes = 0;
2524 char * buf;
2525
2526 time_t tnow;
2527 time_t tstart;
2528 time_t tdiff;
2529 extern volatile int sig_termfast;
2530
2531 if (is_nonblocking == SL_FALSE)
2532 {
2533 /* set to non-blocking mode
2534 */
2535 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2536 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
2537 }
2538
2539 buf = (char *) buf_in;
2540
2541 tstart = time(NULL);
2542 tdiff = 0;
2543
2544 while (count > 0)
2545 {
2546 FD_ZERO(&readfds);
2547 FD_SET(fd, &readfds);
2548
2549 tv.tv_sec = timeout - tdiff;
2550 tv.tv_usec = 0;
2551
2552 retval = select (fd+1, &readfds, NULL, NULL, &tv);
2553
2554 if (retval > 0)
2555 {
2556 byteread = read (fd, buf, count);
2557
2558 if (byteread > 0)
2559 {
2560 bytes += byteread; count -= byteread;
2561 buf += byteread;
2562 if (count == 0)
2563 break;
2564 }
2565 else if (byteread == 0)
2566 {
2567 break;
2568 }
2569 else
2570 {
2571 if (errno == EINTR || errno == EAGAIN)
2572 {
2573 retry_msleep(1, 0);
2574 tnow = time(NULL);
2575 tdiff = tnow - tstart;
2576 continue;
2577 }
2578 else
2579 {
2580 error = errno;
2581 if (is_nonblocking == SL_FALSE)
2582 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2583 TPT(( 0, FIL__, __LINE__, _("msg=<read error>")));
2584 errno = error;
2585 return (SL_EREAD);
2586 }
2587 }
2588 }
2589 else if ((retval == -1) && (errno == EINTR || errno == EAGAIN))
2590 {
2591 retry_msleep(1, 0);
2592 tnow = time(NULL);
2593 tdiff = tnow - tstart;
2594 continue;
2595 }
2596 else if (retval == 0)
2597 {
2598 if (is_nonblocking == SL_FALSE)
2599 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2600 TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
2601 errno = 0;
2602 return (SL_TIMEOUT);
2603 }
2604 else
2605 {
2606 error = errno;
2607 if (is_nonblocking == SL_FALSE)
2608 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2609 TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
2610 errno = error;
2611 return (SL_EREAD);
2612 }
2613
2614 if (sig_termfast == 1)
2615 {
2616 if (is_nonblocking == SL_FALSE)
2617 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2618 TPT(( 0, FIL__, __LINE__, _("msg=<terminated>")));
2619 errno = 0;
2620 return (SL_EREAD);
2621 }
2622
2623 tnow = time(NULL);
2624 tdiff = tnow - tstart;
2625
2626 if (tdiff > timeout)
2627 {
2628 if (is_nonblocking == SL_FALSE)
2629 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2630 TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
2631 errno = 0;
2632 return (SL_TIMEOUT);
2633 }
2634 }
2635
2636 if (is_nonblocking == SL_FALSE)
2637 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2638 return ((int) bytes);
2639}
2640
2641int sl_read_timeout (SL_TICKET ticket, void * buf_in, size_t count,
2642 int timeout, int is_nonblocking)
2643{
2644 int fd, retval;
2645
2646 SL_ENTER(_("sl_read_timeout"));
2647
2648 if (buf_in == NULL || SL_ISERROR(fd = get_the_fd(ticket)))
2649 {
2650 if (buf_in == NULL)
2651 {
2652 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2653 SL_IRETURN((SL_ENULL), _("sl_read_timeout"));
2654 }
2655 if (SL_ISERROR(fd = get_the_fd(ticket)))
2656 {
2657 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2658 SL_IRETURN((fd), _("sl_read_timeout"));
2659 }
2660 }
2661
2662 retval = sl_read_timeout_fd (fd, buf_in, count, timeout, is_nonblocking);
2663 SL_IRETURN((retval), _("sl_read_timeout"));
2664}
2665
2666
2667int sl_read (SL_TICKET ticket, void * buf_in, size_t count)
2668{
2669 int fd;
2670 int byteread = 0;
2671 int bytes = 0;
2672
2673 char * buf;
2674
2675 SL_ENTER(_("sl_read"));
2676
2677 if (count < 1)
2678 {
2679 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
2680 SL_IRETURN((SL_ERANGE), _("sl_read"));
2681 }
2682 if (buf_in == NULL)
2683 {
2684 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2685 SL_IRETURN((SL_ENULL), _("sl_read"));
2686 }
2687
2688 if (SL_ISERROR(fd = get_the_fd(ticket)))
2689 {
2690 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2691 SL_IRETURN((fd), _("sl_read"));
2692 }
2693
2694 buf = (char *) buf_in;
2695
2696 do
2697 {
2698 byteread = read (fd, buf, count);
2699 if (byteread > 0)
2700 {
2701 bytes += byteread; count -= byteread;
2702 buf += byteread;
2703 }
2704 } while ( byteread > 0 ||
2705 ( byteread == -1 && (errno == EINTR || errno == EAGAIN))
2706 );
2707
2708
2709 if (byteread == (-1))
2710 {
2711 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
2712 SL_IRETURN((SL_EREAD), _("sl_read"));
2713 }
2714 SL_IRETURN((bytes), _("sl_read"));
2715}
2716
2717int sl_read_fast (SL_TICKET ticket, void * buf_in, size_t count)
2718{
2719 int fd;
2720 int byteread = 0;
2721
2722 char * buf;
2723
2724 SL_ENTER(_("sl_read_fast"));
2725
2726 if (count < 1)
2727 {
2728 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
2729 SL_IRETURN((SL_ERANGE), _("sl_read_fast"));
2730 }
2731 if (buf_in == NULL)
2732 {
2733 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2734 SL_IRETURN((SL_ENULL), _("sl_read_fast"));
2735 }
2736
2737 if (SL_ISERROR(fd = get_the_fd(ticket)))
2738 {
2739 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2740 SL_IRETURN((fd), _("sl_read_fast"));
2741 }
2742
2743 buf = (char *) buf_in;
2744
2745 do
2746 {
2747 byteread = read (fd, buf, count);
2748 if (byteread >= 0)
2749 {
2750 SL_IRETURN((byteread), _("sl_read_fast"));
2751 }
2752 } while ( byteread == -1 && (errno == EINTR || errno == EAGAIN));
2753
2754
2755 if (byteread == (-1))
2756 {
2757 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
2758 SL_IRETURN((SL_EREAD), _("sl_read_fast"));
2759 }
2760 SL_IRETURN((0), _("sl_read_fast"));
2761}
2762
2763
2764int sl_write (SL_TICKET ticket, const void * msg_in, long nbytes)
2765{
2766 long bytewritten;
2767 long bytecount;
2768 int fd;
2769
2770 const char * msg;
2771
2772 SL_ENTER(_("sl_write"));
2773
2774 if (nbytes < 1)
2775 SL_IRETURN(SL_ERANGE, _("sl_write"));
2776 if (msg_in == NULL)
2777 SL_IRETURN(SL_ENULL, _("sl_write"));
2778 if (SL_ISERROR(fd = get_the_fd(ticket)))
2779 SL_IRETURN(fd, _("sl_write"));
2780
2781 msg = (const char *) msg_in;
2782
2783 /* write
2784 */
2785 bytecount = 0;
2786 bytewritten = 0;
2787 while (bytecount < nbytes)
2788 {
2789 if ((bytewritten = write (fd, msg, nbytes-bytecount)) > 0)
2790 {
2791 bytecount += bytewritten;
2792 msg += bytewritten; /* move buffer pointer forward */
2793 }
2794 else if (bytewritten <= 0)
2795 {
2796 if ( errno == EINTR || errno == EAGAIN) /* try again */
2797 continue;
2798 else
2799 SL_IRETURN(SL_EWRITE, _("sl_write"));
2800 }
2801 }
2802 SL_IRETURN(SL_ENONE, _("sl_write"));
2803}
2804
2805int sl_write_line (SL_TICKET ticket, const void * msg, long nbytes)
2806{
2807 int status;
2808
2809 SL_ENTER(_("sl_write_line"));
2810
2811 status = sl_write(ticket, msg, nbytes);
2812 if (!SL_ISERROR(status))
2813 status = sl_write(ticket, "\n", 1);
2814
2815 SL_IRETURN(status, _("sl_write_line"));
2816}
2817
2818int sl_write_line_fast (SL_TICKET ticket, void * msg, long nbytes)
2819{
2820 int status;
2821 char * p = (char *) msg;
2822
2823 SL_ENTER(_("sl_write_line_fast"));
2824
2825 /* Here nbytes is strlen(msg), so p[nbytes] is the terminating '\0'
2826 * Overwrite the terminator, write out, then write back the terminator.
2827 */
2828 p[nbytes] = '\n';
2829 status = sl_write(ticket, msg, nbytes+1);
2830 p[nbytes] = '\0';
2831
2832 SL_IRETURN(status, _("sl_write_line_fast"));
2833}
2834
2835
2836/* ----------------------------------------------------------------
2837 *
2838 * Trustfile interface
2839 *
2840 * ---------------------------------------------------------------- */
2841
2842extern uid_t rootonly[];
2843extern int EUIDSLOT;
2844extern int ORIG_EUIDSLOT;
2845
2846extern char tf_path[MAXFILENAME]; /* Error path for trust function. */
2847extern uid_t tf_euid; /* Space for EUID of process. */
2848
2849char * sl_error_string(int errorcode)
2850{
2851
2852 switch (errorcode)
2853 {
2854 case SL_EBOGUS:
2855 return _("Bogus file, modified during access");
2856 case SL_EWRITE:
2857 return _("Write error");
2858 case SL_EREAD:
2859 return _("Read error");
2860 case SL_ESYNC:
2861 return _("Error in fsync()");
2862 case SL_EFORWARD:
2863 return _("Error in lseek()");
2864 case SL_EREWIND:
2865 return _("Error in lseek()");
2866 case SL_EUNLINK:
2867 return _("Error in unlink()");
2868 case SL_EMEM:
2869 return _("Out of memory");
2870 case SL_EINTERNAL:
2871 return _("Internal error");
2872 case SL_EINTERNAL01:
2873 return _("Internal error 01");
2874 case SL_EINTERNAL02:
2875 return _("Internal error 02");
2876 case SL_EINTERNAL03:
2877 return _("Internal error 03");
2878 case SL_EINTERNAL04:
2879 return _("Internal error 04");
2880 case SL_EINTERNAL05:
2881 return _("Internal error 05");
2882 case SL_EINTERNAL06:
2883 return _("Internal error 06");
2884 case SL_EINTERNAL07:
2885 return _("Internal error 07");
2886 case SL_EINTERNAL08:
2887 return _("Internal error 08");
2888 case SL_EINTERNAL09:
2889 return _("Internal error 09");
2890 case SL_EINTERNAL10:
2891 return _("Internal error 10");
2892 case SL_EINTERNAL11:
2893 return _("Internal error 11");
2894 case SL_EINTERNAL12:
2895 return _("Internal error 12");
2896 case SL_ETICKET:
2897 return _("Bad ticket");
2898 case SL_EREPEAT:
2899 return _("Illegal repeated use of function");
2900 case SL_ERANGE:
2901 return _("Argument out of range");
2902 case SL_ENULL:
2903 return _("Dereferenced NULL pointer");
2904
2905 case SL_EBADUID:
2906 return _("Owner not trustworthy");
2907 case SL_EBADGID:
2908 return _("Group writeable and member not trustworthy");
2909 case SL_EBADOTH:
2910 return _("World writeable");
2911 case SL_EISDIR:
2912 return _("Is a directory");
2913 case SL_EBADFILE:
2914 return _("File access error");
2915 case SL_EBADNAME:
2916 return _("Invalid filename (prob. too long or null)");
2917
2918 case SL_ETRUNC:
2919 return _("Truncation occured");
2920 case SL_ESTAT:
2921 return _("stat() failed");
2922 case SL_EFSTAT:
2923 return _("fstat() failed");
2924 default:
2925 return _("Unknown error");
2926 }
2927}
2928
2929
2930
2931char * sl_trust_errfile(void)
2932{
2933 return &tf_path[0];
2934}
2935
2936extern uid_t tf_baduid;
2937uid_t sl_trust_baduid(void)
2938{
2939 return tf_baduid;
2940}
2941
2942extern gid_t tf_badgid;
2943gid_t sl_trust_badgid(void)
2944{
2945 return tf_badgid;
2946}
2947
2948
2949static int trust_count = 0;
2950
2951int sl_trust_purge_user (void)
2952{
2953 int i;
2954
2955 EUIDSLOT = ORIG_EUIDSLOT;
2956 trust_count = 0;
2957
2958 for (i = EUIDSLOT; i < (EUIDSLOT + 15); ++i)
2959 rootonly[i] = sh_uid_neg;
2960 return 0;
2961}
2962
2963int sl_trust_add_user (uid_t pwid)
2964{
2965 SL_ENTER(_("sl_trust_add_user"));
2966
2967 if (trust_count == 15)
2968 SL_IRETURN(SL_ERANGE, _("sl_trust_add_user"));
2969
2970 rootonly[EUIDSLOT] = pwid;
2971 ++EUIDSLOT;
2972 ++trust_count;
2973
2974 SL_IRETURN(SL_ENONE, _("sl_trust_add_user"));
2975}
2976
2977#include "sh_mem.h"
2978extern char * sh_util_strdup (const char * str);
2979
2980struct sl_trustfile_store {
2981 char * filename;
2982 uid_t teuid;
2983 struct sl_trustfile_store * next;
2984};
2985
2986static struct sl_trustfile_store * sl_trusted_files = NULL;
2987
2988static void sl_add_trusted_file(const char * filename, uid_t teuid)
2989{
2990 struct sl_trustfile_store *new = SH_ALLOC(sizeof(struct sl_trustfile_store));
2991
2992 new->filename = sh_util_strdup (filename);
2993 new->teuid = teuid;
2994 new->next = sl_trusted_files;
2995
2996 sl_trusted_files = new;
2997 return;
2998}
2999
3000static const char * sl_check_trusted_file(const char * filename, uid_t teuid)
3001{
3002 struct sl_trustfile_store *new = sl_trusted_files;
3003
3004 while (new)
3005 {
3006 if ((new->teuid == teuid) && (0 == strcmp(new->filename, filename)))
3007 return filename;
3008 new = new->next;
3009 }
3010
3011 return NULL;
3012}
3013
3014static void sl_clear_trusted_file(struct sl_trustfile_store * file)
3015{
3016 if (file)
3017 {
3018 if (file->next != NULL)
3019 sl_clear_trusted_file(file->next);
3020 SH_FREE(file->filename);
3021 SH_FREE(file);
3022 }
3023 return;
3024}
3025
3026int sl_trustfile_euid(const char * filename, uid_t teuid)
3027{
3028 long status;
3029 static time_t old = 0;
3030 static time_t now;
3031
3032 SL_ENTER(_("sl_trustfile_euid"));
3033
3034 tf_path[0] = '\0';
3035 if (filename == NULL || filename[0] == '\0')
3036 SL_IRETURN(SL_EBADNAME, _("sl_trustfile_euid"));
3037
3038 now = time(NULL);
3039 if (now < (old + 300))
3040 {
3041 if (NULL != sl_check_trusted_file(filename, teuid))
3042 {
3043 sl_strlcpy(tf_path, filename, sizeof(tf_path));
3044 SL_IRETURN(SL_ENONE, _("sl_trustfile_euid"));
3045 }
3046 }
3047 else
3048 {
3049 sl_clear_trusted_file(sl_trusted_files);
3050 sl_trusted_files = NULL;
3051 old = now;
3052 }
3053
3054 tf_euid = teuid;
3055 status = sl_trustfile(filename, NULL, NULL);
3056 if (status == SL_ENONE)
3057 sl_add_trusted_file(filename, teuid);
3058 SL_IRETURN(status, _("sl_trustfile_euid"));
3059}
3060
3061/* ----------------------------------------------------------------
3062 *
3063 * Overflow tests
3064 *
3065 * ---------------------------------------------------------------- */
3066
3067#ifndef SIZE_MAX
3068#define SIZE_MAX (4294967295U)
3069#endif
3070
3071int sl_ok_muli (int a, int b) /* a*b */
3072{
3073 if ((b == 0) || (a >= (INT_MIN / b) && a <= (INT_MAX / b)))
3074 return SL_TRUE; /* no overflow */
3075 return SL_FALSE;
3076}
3077
3078int sl_ok_muls (size_t a, size_t b) /* a*b */
3079{
3080 if ((b == 0) || (a <= (SIZE_MAX / b)))
3081 return SL_TRUE; /* no overflow */
3082 return SL_FALSE;
3083}
3084
3085int sl_ok_divi (int a, int b) /* a/b */
3086{
3087 (void) a;
3088 if (b != 0)
3089 return SL_TRUE; /* no overflow */
3090 return SL_FALSE;
3091}
3092
3093int sl_ok_addi (int a, int b) /* a+b */
3094{
3095 if (a >= 0 && b >= 0)
3096 {
3097 if (a <= (INT_MAX - b))
3098 return SL_TRUE; /* no overflow */
3099 else
3100 return SL_FALSE;
3101 }
3102 else if (a < 0 && b < 0)
3103 {
3104 if (a >= (INT_MIN - b))
3105 return SL_TRUE; /* no overflow */
3106 else
3107 return SL_FALSE;
3108 }
3109 return SL_TRUE;
3110}
3111
3112int sl_ok_adds (size_t a, size_t b) /* a+b */
3113{
3114 if (a <= (SIZE_MAX - b))
3115 return SL_TRUE; /* no overflow */
3116 else
3117 return SL_FALSE;
3118}
3119
3120int sl_ok_subi (int a, int b) /* a-b */
3121{
3122 if (a >= 0 && b < 0)
3123 {
3124 if (a <= (INT_MAX + b))
3125 return SL_TRUE; /* no overflow */
3126 else
3127 return SL_FALSE;
3128 }
3129 else if (a < 0 && b >= 0)
3130 {
3131 if (a >= (INT_MIN + b))
3132 return SL_TRUE; /* no overflow */
3133 else
3134 return SL_FALSE;
3135 }
3136 return SL_TRUE;
3137}
Note: See TracBrowser for help on using the repository browser.