source: trunk/src/slib.c@ 208

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

Fix compile failures on RHEL3 (ticket #130) and FreeBSD7 amd64 (ticket #131).

File size: 63.9 KB
RevLine 
[1]1#include "config_xor.h"
2
[196]3#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE)
4#define _XOPEN_SOURCE 600
5#define _BSD_SOURCE
6#endif
[1]7
8#include <stdio.h>
9#include <stdlib.h>
10#include <stdarg.h>
11#include <string.h>
[20]12#include <limits.h>
[34]13#ifdef HAVE_STDINT_H
14/* for SIZE_MAX */
15#include <stdint.h>
16#endif
[1]17
18#include <unistd.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <fcntl.h>
22#include <signal.h>
23
[196]24#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE)
25#include <sys/mman.h>
26#endif
27
[1]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
[76]59#define SH_REAL_SET
60
[1]61#include "slib.h"
62#include "sh_calls.h"
63#define SH_NEED_PWD_GRP 1
64#include "sh_static.h"
[144]65#include "sh_pthread.h"
[167]66#include "sh_string.h"
[1]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
[20]116int sl_trace_use (const char * dummy)
[1]117{
[169]118 (void) dummy;
119 slib_do_trace = 1;
[1]120 return 0;
121}
122
[20]123int sl_trace_file (const char * str)
[1]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
[170]133FILE * sl_tracefile_open(const char * file, const char * mode)
[1]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
[170]142void sl_trace_in(const char * str, const char * file, int line)
[1]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);
[169]164 fflush(trace_fp);
[1]165 }
166 else
167 {
168 perror(_("sl_trace_in: fopen"));
169 _exit(1);
170 }
171 }
172 ++trace_level;
173}
174
[170]175void sl_trace_out(const char * str, const char * file, int line)
[1]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);
[169]200 fflush(trace_fp);
[1]201 }
202 else
203 {
204 perror(_("sl_trace_out: fopen"));
205 _exit(1);
206 }
207 }
208}
209
[170]210extern int sh_log_console (const char * msg);
[1]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 */
[170]225int dlog (int flag, const char * file, int line, const char *fmt, ...)
[1]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 {
[22]249 sl_snprintf (val, 81, _("\n--------- %10s "), file);
[1]250 sl_strlcpy (msg, val, 80);
[22]251 sl_snprintf (val, 81, _(" --- %6d ---------\n"), line);
[1]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/*
[76]580 * Have memset in a different translation unit (i.e. this) to prevent
581 * it to get optimized away
[1]582 */
583void *sl_memset(void *s, int c, size_t n)
584{
[76]585 return memset(s, c,n);
[1]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)
[22]783 len = vsnprintf (str, n, format, vl); /* flawfinder: ignore */
[1]784 str[n-1] = '\0';
785#else
[22]786 VA_COPY (vl2, vl); /* save the argument list */
[1]787 total = sl_printf_count (format, vl);
[22]788 len = (int) total;
[1]789 if (total < n)
790 {
[22]791 /* flawfinder: ignore */
[1]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
[22]811 * ETRUNC: truncated (unimplemented)
[1]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)
[22]828 /* flawfinder: ignore */
[1]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 {
[22]836 /* flawfinder: ignore */
[1]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
[76]871 if (!(dst == NULL || src == NULL || *src == '\0'))
872 {
873 if (siz > 0)
874 {
[1]875
[76]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 }
[1]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
[76]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 {
[1]933 if (siz > 0)
934 dst[0] = '\0';
935 return SL_ENONE;
936 }
[76]937 else
938 {
939 return SL_ENULL;
940 }
[1]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
[169]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
[1]1024
[169]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
[1]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
[169]1069 return (-7); /* default to not equal */
[1]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
[169]1087 return (-7); /* default to not equal */
[1]1088}
1089
1090/* string searching
1091 */
1092
[190]1093const char * sl_strstr (const char * haystack, const char * needle)
[1]1094{
1095#ifndef HAVE_STRSTR
[203]1096 unsigned int i;
[1]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 {
[131]1473#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1474 struct passwd pwd;
1475 char buffer[SH_PWBUF_SIZE];
1476 struct passwd * tempres;
1477 sh_getpwnam_r(user, &pwd, buffer, sizeof(buffer), &tempres);
1478#else
1479 struct passwd * tempres = sh_getpwnam(user);
1480#endif
[1]1481
1482 SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1483
1484 rgid_orig = tempres->pw_gid;
1485 ruid_orig = tempres->pw_uid;
1486 }
1487 else
1488 {
1489 rgid_orig = rgid;
1490 ruid_orig = ruid;
1491 }
1492
1493 SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1494 _("sl_drop_privileges() == SL_ENONE"));
1495
1496 suid_is_set = SL_TRUE;
1497 SL_IRETURN(SL_ENONE, _("sl_policy_get_real"));
1498}
1499
1500
1501/*
1502 * Define a policy: Get user.
1503 * Drops privileges.
1504 * Do nothing if not SUID.
1505 */
[170]1506int sl_policy_get_user(const char * user)
[1]1507{
1508 SL_ENTER(_("sl_policy_get_user"));
1509
1510 SL_REQUIRE(user != NULL, _("user != NULL"));
1511 SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1512 SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1513
1514 if (euid != ruid || egid != rgid)
1515 {
[131]1516#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1517 struct passwd pwd;
1518 char buffer[SH_PWBUF_SIZE];
1519 struct passwd * tempres;
1520 sh_getpwnam_r(user, &pwd, buffer, sizeof(buffer), &tempres);
1521#else
1522 struct passwd * tempres = sh_getpwnam(user);
1523#endif
[1]1524
1525 SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1526
1527 SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1528 _("sl_drop_privileges() == SL_ENONE"));
1529 }
1530 SL_IRETURN(SL_ENONE, _("sl_policy_get_user"));
1531}
1532
1533
1534
1535/* ----------------------------------------------------------------
1536 *
1537 * File access routines
1538 *
1539 * ---------------------------------------------------------------- */
1540
1541#define TOFFSET 0x1234
1542
1543/* this would prevent opening files if the first 16 fds are open :( */
1544/* #define MAXFD FOPEN_MAX */
1545
1546#define MAXFD 1024
1547
1548typedef struct openfiles {
1549 SL_TICKET ticket; /* The unique ID. */
1550 int fd; /* The file descriptor. */
1551 char * path; /* The file path. */
[196]1552 int flush; /* Whether we want to flush the cache */
[167]1553 sh_string * content; /* The file content */
[1]1554} SL_OFILE;
1555
1556static SL_OFILE * ofiles[MAXFD];
1557
[144]1558SH_MUTEX_STATIC(mutex_ticket, PTHREAD_MUTEX_INITIALIZER);
[1]1559
1560static unsigned int nonce_counter = TOFFSET;
1561
1562static
1563SL_TICKET sl_create_ticket (unsigned int myindex)
1564{
1565 unsigned int high; /* index */
1566 unsigned int low; /* nonce */
[144]1567 SL_TICKET retval = SL_EINTERNAL;
[1]1568
1569 SL_ENTER(_("sl_create_ticket"));
1570
[144]1571 if (myindex >= MAXFD)
1572 goto out_ticket;
[1]1573
1574 /* mask out the high bit and check that it is not used
1575 * -> verify that it fits into 16 bits as positive
1576 */
1577 high = (myindex + TOFFSET) & 0x7fff;
1578
1579 if (high != myindex + TOFFSET)
[144]1580 goto out_ticket;
[1]1581
[144]1582 SH_MUTEX_LOCK_UNSAFE(mutex_ticket);
1583
[1]1584 low = nonce_counter & 0xffff;
1585
1586 /* Overflow -> nonce too big.
1587 */
1588 if ((low != nonce_counter++) || low == 0)
[144]1589 goto out_ticket;
[1]1590
1591 /* Wrap around the nonce counter.
1592 * This is a dirty trick.
1593 */
1594 if (nonce_counter > 0x7fff)
1595 nonce_counter = TOFFSET;
1596
[144]1597 retval = (SL_TICKET) ((high << 16) | low);
1598
1599 out_ticket:
1600 ;
1601
1602 SH_MUTEX_UNLOCK_UNSAFE(mutex_ticket);
1603 SL_RETURN (retval, _("sl_create_ticket"));
[1]1604}
1605
1606static
1607int sl_read_ticket (SL_TICKET fno)
1608{
1609 register unsigned myindex;
1610 register SL_OFILE *of;
1611
1612 myindex = ((fno >> 16) & 0xffff) - TOFFSET;
1613 if (myindex >= MAXFD)
1614 return (SL_ETICKET);
1615
1616 if (ofiles[myindex] == NULL)
1617 return (SL_ETICKET);
1618
1619 if (ofiles[myindex]->ticket != fno)
1620 return (SL_ETICKET);
1621
1622 if ((of = ofiles[myindex])->fd < 0 || of->fd >= MAXFD )
1623 return (SL_EINTERNAL);
1624
1625 if (((of->ticket) & 0xffff) == 0)
1626 return (SL_EINTERNAL);
1627
1628 return (myindex);
1629}
1630
[76]1631SL_TICKET sl_make_ticket (int fd, const char * filename)
[1]1632{
[22]1633 size_t len;
[1]1634 SL_TICKET ticket;
1635 SL_ENTER(_("sl_make_ticket"));
1636 /* Make entry.
1637 */
1638 if (fd >= MAXFD || fd < 0)
1639 {
1640 SL_IRETURN(SL_TOOMANY, _("sl_make_ticket"));
1641 }
1642
1643 if (ofiles[fd] != NULL)
1644 {
1645 SL_IRETURN(SL_EINTERNAL, _("sl_make_ticket"));
1646 }
1647
1648 if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1649 {
1650 SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1651 }
1652
[22]1653 len = sl_strlen(filename)+1;
1654
1655 if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
[1]1656 {
1657 free(ofiles[fd]);
1658 ofiles[fd] = NULL;
1659 SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1660 }
1661
1662 /* Get a ticket.
1663 */
1664 ticket = sl_create_ticket((unsigned int)fd);
1665
1666 if (SL_ISERROR(ticket))
1667 {
1668 (void) free (ofiles[fd]->path);
1669 (void) free (ofiles[fd]);
1670 SL_IRETURN(ticket, _("sl_make_ticket"));
1671 }
1672
[22]1673 sl_strlcpy (ofiles[fd]->path, filename, len);
[167]1674 ofiles[fd]->ticket = ticket;
1675 ofiles[fd]->fd = fd;
1676 ofiles[fd]->content = NULL;
[196]1677 ofiles[fd]->flush = SL_FALSE;
[1]1678
1679 SL_IRETURN(ticket, _("sl_make_ticket"));
1680}
1681
1682#define SL_OPEN_MIN 113
1683#define SL_OPEN_FOR_READ 113
1684#define SL_OPEN_FOR_WRITE 114
1685#define SL_OPEN_FOR_RDWR 115
1686#define SL_OPEN_FOR_WTRUNC 116
1687#define SL_OPEN_FOR_RWTRUNC 117
1688#define SL_OPEN_SAFE_RDWR 118
1689#define SL_OPEN_FOR_FASTREAD 119
1690#define SL_OPEN_MAX 119
1691
1692#if !defined(O_NOATIME)
1693#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
1694#define O_NOATIME 01000000
1695#else
1696 /*
1697 * bitwise 'or' with zero does not modify any bit
1698 */
1699#define O_NOATIME 0
1700#endif
1701#endif
1702
1703static int o_noatime = O_NOATIME;
1704static mode_t open_mode = (S_IWUSR|S_IRUSR|S_IRGRP);
1705
1706
1707static
[20]1708int sl_open_file (const char *filename, int mode, int priv)
[1]1709{
1710 struct stat lbuf;
1711 struct stat buf;
[192]1712 int errval = 0;
[1]1713 int lstat_return;
1714 int stat_return;
1715 int fd;
1716 int sflags;
[22]1717 size_t len;
[1]1718 SL_TICKET ticket;
1719
1720#if !defined(O_NONBLOCK)
1721#if defined(O_NDELAY)
1722#define O_NONBLOCK O_NDELAY
1723#else
1724#define O_NONBLOCK 0
1725#endif
1726#endif
1727
1728 SL_ENTER(_("sl_open_file"));
1729
1730 if (filename == NULL)
1731 SL_IRETURN(SL_ENULL, _("sl_open_file"));
1732 if (mode < SL_OPEN_MIN || mode > SL_OPEN_MAX)
1733 SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1734
1735 /* "This system call always succeeds and the previous value of
1736 * the mask is returned."
1737 */
1738 (void) umask (0);
1739
1740 if (mode == SL_OPEN_FOR_FASTREAD)
1741 {
1742 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1743 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
[8]1744 /*
[1]1745 if (fd >= 0) {
1746 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1747 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1748 }
[8]1749 */
[1]1750 if (fd < 0)
1751 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1752 goto createTicket;
1753 }
1754
1755#ifdef USE_SUID
1756 if (priv == SL_YESPRIV)
1757 sl_set_suid();
1758#endif
1759 if (mode == SL_OPEN_FOR_READ)
1760 lstat_return = retry_stat (FIL__, __LINE__, filename, &lbuf);
1761 else
1762 lstat_return = retry_lstat(FIL__, __LINE__, filename, &lbuf);
[192]1763 errval = errno;
[1]1764#ifdef USE_SUID
1765 if (priv == SL_YESPRIV)
1766 sl_unset_suid();
1767#endif
1768
1769 if (lstat_return == -1)
1770 {
1771 lstat_return = ENOENT;
1772 if ( (mode == SL_OPEN_FOR_READ && lstat_return == ENOENT) ||
[192]1773 (errval != ENOENT))
[1]1774 {
1775 TPT(( 0, FIL__, __LINE__, _("msg=<lstat: %s> errno=<%d>\n"),
[192]1776 filename, errval));
1777 errno = errval;
1778 SL_IRETURN(SL_ESTAT, _("sl_open_file"));
[1]1779 }
1780 }
1781
1782 if ( (mode != SL_OPEN_FOR_READ) && (lstat_return != ENOENT) &&
1783 ( S_ISDIR(lbuf.st_mode) || (S_IWOTH & lbuf.st_mode) )
1784 )
[192]1785 {
1786 int retval = S_ISDIR(lbuf.st_mode) ? SL_EISDIR : SL_EBADOTH;
1787 errno = 0;
1788 SL_IRETURN(retval, _("sl_open_file"));
1789 }
[1]1790
1791 /* O_NOATIME has an effect for read(). But write() ?.
1792 */
1793 switch (mode)
1794 {
1795 case SL_OPEN_FOR_READ:
1796 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1797 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
[192]1798 errval = errno;
[1]1799 if (fd >= 0) {
1800 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1801 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1802 }
1803 break;
1804 case SL_OPEN_FOR_WRITE:
1805 if (lstat_return == ENOENT)
1806 fd = aud_open (FIL__, __LINE__, priv, filename,
1807 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1808 else
1809 fd = aud_open (FIL__, __LINE__, priv, filename,
1810 O_WRONLY, open_mode);
[192]1811 errval = errno;
[1]1812 break;
1813 case SL_OPEN_SAFE_RDWR:
1814 if (lstat_return == ENOENT)
[192]1815 {
1816 fd = aud_open (FIL__, __LINE__, priv, filename,
1817 O_RDWR|O_CREAT|O_EXCL, open_mode);
1818 errval = errno;
1819 }
[1]1820 else
[192]1821 {
1822 errno = errval;
1823 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1824 }
[1]1825 break;
1826 case SL_OPEN_FOR_RDWR:
1827 if (lstat_return == ENOENT)
[192]1828 fd = aud_open (FIL__, __LINE__, priv, filename,
1829 O_RDWR|O_CREAT|O_EXCL, open_mode);
[1]1830 else
1831 fd = aud_open (FIL__, __LINE__, priv, filename,
1832 O_RDWR, open_mode);
[192]1833 errval = errno;
[1]1834 break;
1835 case SL_OPEN_FOR_WTRUNC:
1836 if (lstat_return == ENOENT)
1837 fd = aud_open (FIL__, __LINE__, priv, filename,
1838 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1839 else
1840 fd = aud_open (FIL__, __LINE__, priv, filename,
1841 O_WRONLY|O_TRUNC, open_mode);
[192]1842 errval = errno;
[1]1843 break;
1844 case SL_OPEN_FOR_RWTRUNC:
1845 if (lstat_return == ENOENT)
1846 fd = aud_open (FIL__, __LINE__, priv, filename,
1847 O_RDWR|O_CREAT|O_EXCL, open_mode);
1848 else
1849 fd = aud_open (FIL__, __LINE__, priv, filename,
1850 O_RDWR|O_TRUNC, open_mode);
[192]1851 errval = errno;
[1]1852 break;
1853 default:
[192]1854 errno = 0;
[1]1855 SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1856 }
1857
1858 if (fd < 0)
1859 {
1860 TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s> errno=<%d>\n"),
[192]1861 filename, errval));
1862 errno = errval;
[1]1863 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1864 }
1865
1866#ifdef USE_SUID
1867 if (priv == SL_YESPRIV)
1868 sl_set_suid();
1869#endif
1870 stat_return = retry_fstat(FIL__, __LINE__, fd, &buf);
[192]1871 errval = errno;
[1]1872#ifdef USE_SUID
1873 if (priv == SL_YESPRIV)
1874 sl_unset_suid();
1875#endif
1876
1877 if (stat_return < 0)
1878 {
1879 close (fd);
[192]1880 errno = errval;
1881 SL_IRETURN(SL_EFSTAT, _("sl_open_file"));
[1]1882 }
1883
[192]1884 errno = 0;
1885
[1]1886 if (lstat_return != ENOENT && buf.st_ino != lbuf.st_ino)
1887 {
1888 close (fd);
1889 SL_IRETURN(SL_EBOGUS, _("sl_open_file"));
1890 }
1891
1892 createTicket:
1893
1894 /* Make entry.
1895 */
1896 if (fd >= MAXFD)
1897 {
1898 close(fd);
1899 SL_IRETURN(SL_TOOMANY, _("sl_open_file"));
1900 }
1901
1902 if (ofiles[fd] != NULL)
1903 {
1904 close(fd);
1905 SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1906 }
1907
1908 if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1909 {
1910 close(fd);
1911 SL_IRETURN(SL_EMEM, _("sl_open_file"));
1912 }
1913
[22]1914 len = sl_strlen(filename)+1;
1915
1916 if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
[1]1917 {
1918 free(ofiles[fd]);
1919 ofiles[fd] = NULL;
1920 close(fd);
1921 SL_IRETURN(SL_EMEM, _("sl_open_file"));
1922 }
1923
1924 /* Get a ticket.
1925 */
1926 ticket = sl_create_ticket(fd);
1927
1928 if (SL_ISERROR(ticket))
1929 {
1930 (void) free (ofiles[fd]->path);
1931 (void) free (ofiles[fd]);
1932 close(fd);
1933 SL_IRETURN(ticket, _("sl_open_file"));
1934 }
1935
[22]1936 sl_strlcpy (ofiles[fd]->path, filename, len);
[167]1937 ofiles[fd]->ticket = ticket;
1938 ofiles[fd]->fd = fd;
1939 ofiles[fd]->content = NULL;
[196]1940 ofiles[fd]->flush = SL_FALSE;
[1]1941
1942 SL_IRETURN(ticket, _("sl_open_file"));
1943}
1944
[196]1945int get_the_fd (SL_TICKET ticket)
1946{
1947 int fd;
1948
1949 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
1950 return (fd);
1951
1952 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
1953 return (SL_EINTERNAL);
1954 return (fd);
1955}
1956
[1]1957static
[20]1958int check_fname_priv (const char * fname, int priv)
[1]1959{
1960 SL_ENTER(_("check_fname_priv"));
1961 if (fname == NULL)
1962 SL_IRETURN(SL_ENULL, _("check_fname_priv"));
1963 if (priv != SL_YESPRIV && priv != SL_NOPRIV)
1964 SL_IRETURN(SL_EINTERNAL, _("check_fname_priv"));
1965 SL_IRETURN(SL_ENONE, _("check_fname_priv"));
1966}
1967
[20]1968SL_TICKET sl_open_write (const char * fname, int priv)
[1]1969{
1970 long status;
1971 SL_ENTER(_("sl_open_write"));
1972
1973 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1974 SL_IRETURN(status, _("sl_open_write"));
1975
1976 status = sl_open_file(fname, SL_OPEN_FOR_WRITE, priv);
1977 SL_IRETURN(status, _("sl_open_write"));
1978}
1979
[20]1980SL_TICKET sl_open_read (const char * fname, int priv)
[1]1981{
1982 long status;
1983 SL_ENTER(_("sl_open_read"));
1984
1985 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1986 {
1987 TPT(( 0, FIL__, __LINE__,
1988 _("msg=<Error in check_fname_priv.> status=<%ld>\n"),
1989 status));
1990 SL_IRETURN(status, _("sl_open_read"));
1991 }
1992
1993 status = sl_open_file(fname, SL_OPEN_FOR_READ, priv);
1994 SL_IRETURN(status, _("sl_open_read"));
1995}
1996
[196]1997#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
1998static int sl_check_mincore(int fd)
1999{
2000 /* Idea from Tobias Oetiker (http://insights.oetiker.ch/linux/fadvise.html)
2001 */
2002 struct stat fbuf;
2003 int retval = -1;
2004
2005 if (0 == fstat(fd, &fbuf))
2006 {
2007 void *f_map;
2008
2009 f_map = mmap((void *)0, fbuf.st_size, PROT_NONE, MAP_SHARED, fd, 0);
2010 if (MAP_FAILED != f_map)
2011 {
2012 extern int sh_unix_pagesize(void);
2013 size_t i;
2014 size_t page_size = sh_unix_pagesize();
2015 size_t vec_size = (fbuf.st_size+page_size-1)/page_size;
2016 unsigned char * vec = calloc(1, vec_size);
2017
2018 if (vec)
2019 {
2020 mincore(f_map, fbuf.st_size, vec);
2021 // imax = fbuf.st_size/page_size;
2022 for (i = 0; i <= vec_size; ++i)
2023 {
2024 if (vec[i]&1)
2025 {
2026 goto incore;
2027 }
2028 }
2029 retval = 0;
2030 incore:
2031 free(vec);
2032 }
2033 munmap(f_map, fbuf.st_size);
2034 }
2035 }
2036 return retval;
2037}
2038#endif
2039
2040static int sl_drop_cache = SL_FALSE;
2041
2042int sl_set_drop_cache(const char * str)
2043{
2044 extern int sh_util_flagval(const char * c, int * fval);
2045 return sh_util_flagval(str, &sl_drop_cache);
2046}
2047
[20]2048SL_TICKET sl_open_fastread (const char * fname, int priv)
[1]2049{
2050 long status;
2051 SL_ENTER(_("sl_open_fastread"));
2052
2053 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2054 SL_IRETURN(status, _("sl_open_read"));
2055
2056 status = sl_open_file(fname, SL_OPEN_FOR_FASTREAD, priv);
[196]2057
2058#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
2059
2060 if (SL_FALSE != sl_drop_cache && !SL_ISERROR(status))
2061 {
2062 int fd = get_the_fd(status);
2063 if (fd >= 0)
2064 {
2065 if (0 == sl_check_mincore(fd))
2066 ofiles[fd]->flush = SL_TRUE;
2067 }
2068 }
2069
2070#endif
2071
[1]2072 SL_IRETURN(status, _("sl_open_fastread"));
2073}
2074
[20]2075SL_TICKET sl_open_rdwr (const char * fname, int priv)
[1]2076{
2077 long status;
2078 SL_ENTER(_("sl_open_rdwr"));
2079
2080 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2081 SL_IRETURN(status, _("sl_open_rdwr"));
2082
2083 status = sl_open_file(fname, SL_OPEN_FOR_RDWR, priv);
2084 SL_IRETURN(status, _("sl_open_rdwr"));
2085}
2086
[20]2087SL_TICKET sl_open_safe_rdwr (const char * fname, int priv)
[1]2088{
2089 long status;
2090 SL_ENTER(_("sl_open_safe_rdwr"));
2091
2092 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2093 SL_IRETURN(status, _("sl_open_safe_rdwr"));
2094
2095 status = sl_open_file(fname, SL_OPEN_SAFE_RDWR, priv);
2096 SL_IRETURN(status, _("sl_open_safe_rdwr"));
2097}
2098
[20]2099SL_TICKET sl_open_write_trunc (const char * fname, int priv)
[1]2100{
2101 long status;
2102 SL_ENTER(_("sl_open_write_trunc"));
2103
2104 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2105 SL_IRETURN(status, _("sl_open_write_trunc"));
2106
2107 status = sl_open_file(fname, SL_OPEN_FOR_WTRUNC, priv);
2108 SL_IRETURN(status, _("sl_open_write_trunc"));
2109}
2110
[20]2111SL_TICKET sl_open_rdwr_trunc (const char * fname, int priv)
[1]2112{
2113 long status;
2114 SL_ENTER(_("sl_open_rdwr_trunc"));
2115
2116 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2117 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
2118
2119 status = sl_open_file(fname, SL_OPEN_FOR_RWTRUNC, priv);
2120 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
2121}
2122
2123
[167]2124int sl_init_content (SL_TICKET ticket, size_t size)
2125{
2126 int fd;
2127
2128 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2129 return (fd);
2130
2131 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
2132 return (SL_EINTERNAL);
2133
2134 if (ofiles[fd]->content)
2135 sh_string_destroy(&(ofiles[fd]->content));
2136 ofiles[fd]->content = sh_string_new(size);
2137
2138 return SL_ENONE;
2139}
2140
2141sh_string * sl_get_content (SL_TICKET ticket)
2142{
2143 int fd;
2144
2145 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2146 return (NULL);
2147
2148 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
2149 return (NULL);
2150
2151 return (ofiles[fd]->content);
2152}
2153
[1]2154int sl_close (SL_TICKET ticket)
2155{
2156 register int fd;
2157
2158 SL_ENTER(_("sl_close"));
2159
2160 if (SL_ISERROR(fd = get_the_fd (ticket)))
2161 SL_IRETURN(fd, _("sl_close"));
2162
[196]2163#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
2164
2165 if (ofiles[fd]->flush == SL_TRUE)
2166 {
2167 posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
2168 }
2169
2170#endif
2171
[1]2172 /* This may fail, but what to do then ?
2173 */
2174 if (0 != close(fd) && ofiles[fd] != NULL)
2175 {
2176 TPT((0, FIL__, __LINE__,
[29]2177 _("msg=<Error closing file.>, path=<%s>, fd=<%d>, err=<%s>\n"),
2178 ofiles[fd]->path, fd, strerror(errno)));
[1]2179 }
2180
2181 if (ofiles[fd] != NULL)
2182 {
[167]2183 if (ofiles[fd]->content)
2184 sh_string_destroy(&(ofiles[fd]->content));
[1]2185 (void) free(ofiles[fd]->path);
2186 (void) free(ofiles[fd]);
2187 ofiles[fd] = NULL;
2188 }
2189
2190 SL_IRETURN(SL_ENONE, _("sl_close"));
2191}
2192
2193int sl_dropall(int fd, int except)
2194{
2195 while (fd < MAXFD)
2196 {
2197 if (ofiles[fd] != NULL && fd != except)
2198 {
[167]2199 if (ofiles[fd]->content)
2200 sh_string_destroy(&(ofiles[fd]->content));
[1]2201 if (ofiles[fd]->path != NULL)
2202 (void) free(ofiles[fd]->path);
2203 (void) free(ofiles[fd]);
2204 ofiles[fd] = NULL;
2205 }
2206 ++fd;
2207 }
2208 return 0;
2209}
2210
[174]2211int sl_dropall_dirty(int fd, int except)
2212{
2213 while (fd < MAXFD)
2214 {
2215 if (ofiles[fd] != NULL && fd != except)
2216 {
2217 ofiles[fd] = NULL;
2218 }
2219 ++fd;
2220 }
2221 return 0;
2222}
[1]2223
[174]2224
[1]2225int sl_unlink (SL_TICKET ticket)
2226{
2227 register int fd;
2228
2229 SL_ENTER(_("sl_unlink"));
2230
2231 if (SL_ISERROR(fd = get_the_fd(ticket)))
2232 SL_IRETURN(fd, _("sl_unlink"));
2233
2234 if (retry_aud_unlink(FIL__, __LINE__, ofiles[fd]->path) < 0)
2235 SL_IRETURN(SL_EUNLINK, _("sl_unlink"));
2236
2237 SL_IRETURN(SL_ENONE, _("sl_unlink"));
2238}
2239
2240
2241int sl_seek (SL_TICKET ticket, off_t off_data)
2242{
2243 register int fd;
2244
2245 SL_ENTER(_("sl_seek"));
2246
2247 if (SL_ISERROR(fd = get_the_fd(ticket)))
2248 SL_IRETURN(fd, _("sl_seek"));
2249
2250 if (lseek(fd, off_data, SEEK_SET) == (off_t)-1)
2251 SL_IRETURN(SL_EREWIND, _("sl_seek"));
2252
2253 SL_IRETURN(SL_ENONE, _("sl_seek"));
2254}
2255
2256int sl_rewind (SL_TICKET ticket)
2257{
2258 register int fd;
2259
2260 SL_ENTER(_("sl_rewind"));
2261
2262 if (SL_ISERROR(fd = get_the_fd(ticket)))
2263 SL_IRETURN(fd, _("sl_rewind"));
2264
2265 if (lseek (fd, 0L, SEEK_SET) == (off_t)-1)
2266 SL_IRETURN(SL_EREWIND, _("sl_rewind"));
2267
2268 SL_IRETURN(SL_ENONE, _("sl_rewind"));
2269}
2270
2271int sl_forward (SL_TICKET ticket)
2272{
2273 register int fd;
2274
2275 SL_ENTER(_("sl_forward"));
2276
2277 if (SL_ISERROR(fd = get_the_fd(ticket)))
2278 SL_IRETURN(fd, _("sl_forward"));
2279
2280 if (lseek (fd, 0L, SEEK_END) == (off_t)-1)
2281 SL_IRETURN(SL_EFORWARD, _("sl_forward"));
2282
2283 SL_IRETURN(SL_ENONE, _("sl_forward"));
2284}
2285
2286
2287int sl_sync (SL_TICKET ticket)
2288{
2289 register int fd;
2290
2291 SL_ENTER(_("sl_sync"));
2292
2293 if (SL_ISERROR(fd = get_the_fd(ticket)))
2294 SL_IRETURN(fd, _("sl_sync"));
2295
2296 if (fsync (fd) == -1)
2297 SL_IRETURN(SL_ESYNC, _("sl_sync"));
2298
2299 SL_IRETURN(SL_ENONE, _("sl_sync"));
2300}
2301
[8]2302int sl_read_timeout_prep (SL_TICKET ticket)
2303{
2304 int fd;
2305 int sflags;
[1]2306
[8]2307 SL_ENTER(_("sl_read_timeout_prep"));
2308
2309 if (SL_ISERROR(fd = get_the_fd(ticket)))
2310 {
2311 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2312 SL_IRETURN(fd, _("sl_read_timeout_prep"));
2313 }
2314
2315 /* set to non-blocking mode
2316 */
2317 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2318 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
2319
2320 SL_IRETURN(SL_ENONE, _("sl_read_timeout_prep"));
2321}
2322
[131]2323
2324int sl_read_timeout_fd (int fd, void * buf_in, size_t count,
2325 int timeout, int is_nonblocking)
[1]2326{
[137]2327 int sflags = 0;
[1]2328 fd_set readfds;
2329 struct timeval tv;
[8]2330 /* int sflags; */
[1]2331 int retval;
[192]2332 int error;
[1]2333
2334 int byteread = 0;
2335 int bytes = 0;
2336 char * buf;
2337
2338 time_t tnow;
2339 time_t tstart;
2340 time_t tdiff;
2341 extern volatile int sig_termfast;
2342
[131]2343 if (is_nonblocking == SL_FALSE)
[1]2344 {
[131]2345 /* set to non-blocking mode
2346 */
2347 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2348 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
[1]2349 }
2350
2351 buf = (char *) buf_in;
2352
2353 tstart = time(NULL);
2354 tdiff = 0;
2355
2356 while (count > 0)
2357 {
2358 FD_ZERO(&readfds);
2359 FD_SET(fd, &readfds);
2360
2361 tv.tv_sec = timeout - tdiff;
2362 tv.tv_usec = 0;
2363
2364 retval = select (fd+1, &readfds, NULL, NULL, &tv);
2365
2366 if (retval > 0)
2367 {
2368 byteread = read (fd, buf, count);
[8]2369
2370 if (byteread > 0)
[1]2371 {
2372 bytes += byteread; count -= byteread;
2373 buf += byteread;
2374 if (count == 0)
2375 break;
2376 }
2377 else if (byteread == 0)
2378 {
2379 break;
2380 }
2381 else
2382 {
2383 if (errno == EINTR || errno == EAGAIN)
2384 {
2385 retry_msleep(1, 0);
2386 tnow = time(NULL);
2387 tdiff = tnow - tstart;
2388 continue;
2389 }
2390 else
2391 {
[192]2392 error = errno;
[131]2393 if (is_nonblocking == SL_FALSE)
2394 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2395 TPT(( 0, FIL__, __LINE__, _("msg=<read error>")));
[192]2396 errno = error;
[1]2397 return (SL_EREAD);
2398 }
2399 }
2400 }
2401 else if ((retval == -1) && (errno == EINTR || errno == EAGAIN))
2402 {
2403 retry_msleep(1, 0);
2404 tnow = time(NULL);
2405 tdiff = tnow - tstart;
2406 continue;
2407 }
2408 else if (retval == 0)
2409 {
[131]2410 if (is_nonblocking == SL_FALSE)
2411 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2412 TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
[192]2413 errno = 0;
[1]2414 return (SL_TIMEOUT);
2415 }
2416 else
2417 {
[192]2418 error = errno;
[131]2419 if (is_nonblocking == SL_FALSE)
2420 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2421 TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
[192]2422 errno = error;
[1]2423 return (SL_EREAD);
2424 }
[8]2425
2426 if (sig_termfast == 1)
2427 {
[131]2428 if (is_nonblocking == SL_FALSE)
2429 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2430 TPT(( 0, FIL__, __LINE__, _("msg=<terminated>")));
[192]2431 errno = 0;
[8]2432 return (SL_EREAD);
2433 }
2434
[1]2435 tnow = time(NULL);
2436 tdiff = tnow - tstart;
[8]2437
2438 if (tdiff > timeout)
2439 {
[131]2440 if (is_nonblocking == SL_FALSE)
2441 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2442 TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
[192]2443 errno = 0;
[8]2444 return (SL_TIMEOUT);
2445 }
[1]2446 }
2447
[131]2448 if (is_nonblocking == SL_FALSE)
2449 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[1]2450 return ((int) bytes);
2451}
2452
[131]2453int sl_read_timeout (SL_TICKET ticket, void * buf_in, size_t count,
2454 int timeout, int is_nonblocking)
2455{
[169]2456 int fd, retval;
[131]2457
[169]2458 SL_ENTER(_("sl_read_timeout"));
2459
[131]2460 if (buf_in == NULL || SL_ISERROR(fd = get_the_fd(ticket)))
2461 {
2462 if (buf_in == NULL)
2463 {
2464 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
[169]2465 SL_IRETURN((SL_ENULL), _("sl_read_timeout"));
[131]2466 }
2467 if (SL_ISERROR(fd = get_the_fd(ticket)))
2468 {
2469 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
[169]2470 SL_IRETURN((fd), _("sl_read_timeout"));
[131]2471 }
2472 }
[1]2473
[169]2474 retval = sl_read_timeout_fd (fd, buf_in, count, timeout, is_nonblocking);
2475 SL_IRETURN((retval), _("sl_read_timeout"));
[131]2476}
2477
2478
[1]2479int sl_read (SL_TICKET ticket, void * buf_in, size_t count)
2480{
2481 int fd;
2482 int byteread = 0;
2483 int bytes = 0;
2484
2485 char * buf;
2486
[169]2487 SL_ENTER(_("sl_read"));
2488
[1]2489 if (count < 1)
2490 {
2491 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
[169]2492 SL_IRETURN((SL_ERANGE), _("sl_read"));
[1]2493 }
2494 if (buf_in == NULL)
2495 {
2496 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
[169]2497 SL_IRETURN((SL_ENULL), _("sl_read"));
[1]2498 }
2499
2500 if (SL_ISERROR(fd = get_the_fd(ticket)))
2501 {
2502 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
[169]2503 SL_IRETURN((fd), _("sl_read"));
[1]2504 }
2505
2506 buf = (char *) buf_in;
2507
2508 do
2509 {
2510 byteread = read (fd, buf, count);
2511 if (byteread > 0)
2512 {
2513 bytes += byteread; count -= byteread;
2514 buf += byteread;
2515 }
2516 } while ( byteread > 0 ||
[5]2517 ( byteread == -1 && (errno == EINTR || errno == EAGAIN))
[1]2518 );
2519
2520
2521 if (byteread == (-1))
2522 {
2523 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
[169]2524 SL_IRETURN((SL_EREAD), _("sl_read"));
[1]2525 }
[169]2526 SL_IRETURN((bytes), _("sl_read"));
[1]2527}
2528
2529int sl_read_fast (SL_TICKET ticket, void * buf_in, size_t count)
2530{
2531 int fd;
2532 int byteread = 0;
2533
2534 char * buf;
2535
[169]2536 SL_ENTER(_("sl_read_fast"));
2537
[1]2538 if (count < 1)
2539 {
2540 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
[169]2541 SL_IRETURN((SL_ERANGE), _("sl_read_fast"));
[1]2542 }
2543 if (buf_in == NULL)
2544 {
2545 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
[169]2546 SL_IRETURN((SL_ENULL), _("sl_read_fast"));
[1]2547 }
2548
2549 if (SL_ISERROR(fd = get_the_fd(ticket)))
2550 {
2551 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
[169]2552 SL_IRETURN((fd), _("sl_read_fast"));
[1]2553 }
2554
2555 buf = (char *) buf_in;
2556
2557 do
2558 {
2559 byteread = read (fd, buf, count);
2560 if (byteread >= 0)
2561 {
[169]2562 SL_IRETURN((byteread), _("sl_read_fast"));
[1]2563 }
[5]2564 } while ( byteread == -1 && (errno == EINTR || errno == EAGAIN));
[1]2565
2566
2567 if (byteread == (-1))
2568 {
2569 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
[169]2570 SL_IRETURN((SL_EREAD), _("sl_read_fast"));
[1]2571 }
[169]2572 SL_IRETURN((0), _("sl_read_fast"));
[1]2573}
2574
2575
[170]2576int sl_write (SL_TICKET ticket, const void * msg_in, long nbytes)
[1]2577{
2578 long bytewritten;
2579 long bytecount;
2580 int fd;
2581
[170]2582 const char * msg;
[1]2583
2584 SL_ENTER(_("sl_write"));
2585
2586 if (nbytes < 1)
2587 SL_IRETURN(SL_ERANGE, _("sl_write"));
2588 if (msg_in == NULL)
2589 SL_IRETURN(SL_ENULL, _("sl_write"));
2590 if (SL_ISERROR(fd = get_the_fd(ticket)))
2591 SL_IRETURN(fd, _("sl_write"));
2592
[170]2593 msg = (const char *) msg_in;
[1]2594
2595 /* write
2596 */
2597 bytecount = 0;
2598 bytewritten = 0;
2599 while (bytecount < nbytes)
2600 {
2601 if ((bytewritten = write (fd, msg, nbytes-bytecount)) > 0)
2602 {
2603 bytecount += bytewritten;
2604 msg += bytewritten; /* move buffer pointer forward */
2605 }
2606 else if (bytewritten <= 0)
2607 {
2608 if ( errno == EINTR || errno == EAGAIN) /* try again */
2609 continue;
2610 else
2611 SL_IRETURN(SL_EWRITE, _("sl_write"));
2612 }
2613 }
2614 SL_IRETURN(SL_ENONE, _("sl_write"));
2615}
2616
[170]2617int sl_write_line (SL_TICKET ticket, const void * msg, long nbytes)
[1]2618{
2619 int status;
2620
2621 SL_ENTER(_("sl_write_line"));
2622
2623 status = sl_write(ticket, msg, nbytes);
2624 if (!SL_ISERROR(status))
2625 status = sl_write(ticket, "\n", 1);
2626
2627 SL_IRETURN(status, _("sl_write_line"));
2628}
2629
[76]2630int sl_write_line_fast (SL_TICKET ticket, void * msg, long nbytes)
2631{
2632 int status;
2633 char * p = (char *) msg;
[1]2634
[76]2635 SL_ENTER(_("sl_write_line_fast"));
2636
2637 /* Here nbytes is strlen(msg), so p[nbytes] is the terminating '\0'
2638 * Overwrite the terminator, write out, then write back the terminator.
2639 */
2640 p[nbytes] = '\n';
2641 status = sl_write(ticket, msg, nbytes+1);
2642 p[nbytes] = '\0';
2643
2644 SL_IRETURN(status, _("sl_write_line_fast"));
2645}
2646
2647
[1]2648/* ----------------------------------------------------------------
2649 *
2650 * Trustfile interface
2651 *
2652 * ---------------------------------------------------------------- */
2653
2654extern uid_t rootonly[];
2655extern int EUIDSLOT;
2656extern int ORIG_EUIDSLOT;
2657
2658extern char tf_path[MAXFILENAME]; /* Error path for trust function. */
2659extern uid_t tf_euid; /* Space for EUID of process. */
2660
2661char * sl_error_string(int errorcode)
2662{
[192]2663
[1]2664 switch (errorcode)
2665 {
2666 case SL_EBOGUS:
[200]2667 return _("Bogus file. Modified during access");
[1]2668 case SL_EWRITE:
[200]2669 return _("Write error");
[1]2670 case SL_EREAD:
[200]2671 return _("Read error");
[1]2672 case SL_ESYNC:
[200]2673 return _("Error in fsync()");
[1]2674 case SL_EFORWARD:
[200]2675 return _("Error in lseek()");
[1]2676 case SL_EREWIND:
[200]2677 return _("Error in lseek()");
[1]2678 case SL_EUNLINK:
[200]2679 return _("Error in unlink()");
[1]2680 case SL_EMEM:
[200]2681 return _("Out of memory");
[1]2682 case SL_EINTERNAL:
[200]2683 return _("Internal error");
[1]2684 case SL_ETICKET:
[200]2685 return _("Bad ticket");
[1]2686 case SL_EREPEAT:
[200]2687 return _("Illegal repeated use of function");
[1]2688 case SL_ERANGE:
[200]2689 return _("Argument out of range");
[1]2690 case SL_ENULL:
[200]2691 return _("Dereferenced NULL pointer");
[1]2692
2693 case SL_EBADUID:
[200]2694 return _("Owner not trustworthy");
[1]2695 case SL_EBADGID:
[200]2696 return _("Group writeable and member not trustworthy");
[1]2697 case SL_EBADOTH:
[200]2698 return _("World writeable");
[192]2699 case SL_EISDIR:
[200]2700 return _("Is a directory");
[1]2701 case SL_EBADFILE:
[200]2702 return _("File access error");
[1]2703 case SL_EBADNAME:
[200]2704 return _("Invalid filename (prob. too long or null)");
[1]2705
2706 case SL_ETRUNC:
[200]2707 return _("Truncation occured");
[1]2708 case SL_ESTAT:
[200]2709 return _("stat() failed");
[192]2710 case SL_EFSTAT:
[200]2711 return _("fstat() failed");
[1]2712 default:
[200]2713 return _("Unknown error");
[1]2714 }
2715}
2716
2717
2718
[170]2719char * sl_trust_errfile(void)
[1]2720{
2721 return &tf_path[0];
2722}
2723
2724extern uid_t tf_baduid;
[170]2725uid_t sl_trust_baduid(void)
[1]2726{
2727 return tf_baduid;
2728}
2729
2730extern gid_t tf_badgid;
[170]2731gid_t sl_trust_badgid(void)
[1]2732{
2733 return tf_badgid;
2734}
2735
2736
2737static int trust_count = 0;
2738
[170]2739int sl_trust_purge_user (void)
[1]2740{
2741 int i;
2742
2743 EUIDSLOT = ORIG_EUIDSLOT;
2744 trust_count = 0;
2745
2746 for (i = EUIDSLOT; i < (EUIDSLOT + 15); ++i)
2747 rootonly[i] = sh_uid_neg;
2748 return 0;
2749}
2750
2751int sl_trust_add_user (uid_t pwid)
2752{
2753 SL_ENTER(_("sl_trust_add_user"));
2754
2755 if (trust_count == 15)
2756 SL_IRETURN(SL_ERANGE, _("sl_trust_add_user"));
2757
2758 rootonly[EUIDSLOT] = pwid;
2759 ++EUIDSLOT;
2760 ++trust_count;
2761
2762 SL_IRETURN(SL_ENONE, _("sl_trust_add_user"));
2763}
2764
[76]2765#include "sh_mem.h"
2766extern char * sh_util_strdup (const char * str);
2767
2768struct sl_trustfile_store {
2769 char * filename;
2770 uid_t teuid;
2771 struct sl_trustfile_store * next;
2772};
2773
2774static struct sl_trustfile_store * sl_trusted_files = NULL;
2775
[183]2776static void sl_add_trusted_file(const char * filename, uid_t teuid)
[76]2777{
2778 struct sl_trustfile_store *new = SH_ALLOC(sizeof(struct sl_trustfile_store));
2779
2780 new->filename = sh_util_strdup (filename);
2781 new->teuid = teuid;
2782 new->next = sl_trusted_files;
2783
2784 sl_trusted_files = new;
2785 return;
2786}
2787
[183]2788static const char * sl_check_trusted_file(const char * filename, uid_t teuid)
[76]2789{
2790 struct sl_trustfile_store *new = sl_trusted_files;
2791
2792 while (new)
2793 {
2794 if ((new->teuid == teuid) && (0 == strcmp(new->filename, filename)))
2795 return filename;
2796 new = new->next;
2797 }
2798
2799 return NULL;
2800}
2801
[183]2802static void sl_clear_trusted_file(struct sl_trustfile_store * file)
[76]2803{
2804 if (file)
2805 {
2806 if (file->next != NULL)
2807 sl_clear_trusted_file(file->next);
2808 SH_FREE(file->filename);
2809 SH_FREE(file);
2810 }
2811 return;
2812}
2813
[183]2814int sl_trustfile_euid(const char * filename, uid_t teuid)
[1]2815{
[76]2816 long status;
2817 static time_t old = 0;
2818 static time_t now;
2819
[1]2820 SL_ENTER(_("sl_trustfile_euid"));
2821
2822 tf_path[0] = '\0';
2823 if (filename == NULL || filename[0] == '\0')
2824 SL_IRETURN(SL_EBADNAME, _("sl_trustfile_euid"));
2825
[76]2826 now = time(NULL);
2827 if (now < (old + 300))
2828 {
2829 if (NULL != sl_check_trusted_file(filename, teuid))
2830 {
2831 sl_strlcpy(tf_path, filename, sizeof(tf_path));
2832 SL_IRETURN(SL_ENONE, _("sl_trustfile_euid"));
2833 }
2834 }
2835 else
2836 {
2837 sl_clear_trusted_file(sl_trusted_files);
2838 sl_trusted_files = NULL;
2839 old = now;
2840 }
2841
[1]2842 tf_euid = teuid;
2843 status = sl_trustfile(filename, NULL, NULL);
[76]2844 if (status == SL_ENONE)
2845 sl_add_trusted_file(filename, teuid);
[1]2846 SL_IRETURN(status, _("sl_trustfile_euid"));
2847}
2848
[20]2849/* ----------------------------------------------------------------
2850 *
2851 * Overflow tests
2852 *
2853 * ---------------------------------------------------------------- */
[1]2854
[34]2855#ifndef SIZE_MAX
2856#define SIZE_MAX (4294967295U)
2857#endif
2858
[20]2859int sl_ok_muli (int a, int b) /* a*b */
2860{
[34]2861 if ((b == 0) || (a >= (INT_MIN / b) && a <= (INT_MAX / b)))
[20]2862 return SL_TRUE; /* no overflow */
2863 return SL_FALSE;
2864}
2865
[34]2866int sl_ok_muls (size_t a, size_t b) /* a*b */
2867{
2868 if ((b == 0) || (a <= (SIZE_MAX / b)))
2869 return SL_TRUE; /* no overflow */
2870 return SL_FALSE;
2871}
2872
[20]2873int sl_ok_divi (int a, int b) /* a/b */
2874{
2875 (void) a;
2876 if (b != 0)
2877 return SL_TRUE; /* no overflow */
2878 return SL_FALSE;
2879}
2880
2881int sl_ok_addi (int a, int b) /* a+b */
2882{
2883 if (a >= 0 && b >= 0)
2884 {
2885 if (a <= (INT_MAX - b))
2886 return SL_TRUE; /* no overflow */
2887 else
2888 return SL_FALSE;
2889 }
2890 else if (a < 0 && b < 0)
2891 {
2892 if (a >= (INT_MIN - b))
2893 return SL_TRUE; /* no overflow */
2894 else
2895 return SL_FALSE;
2896 }
2897 return SL_TRUE;
2898}
2899
[34]2900int sl_ok_adds (size_t a, size_t b) /* a+b */
2901{
2902 if (a <= (SIZE_MAX - b))
2903 return SL_TRUE; /* no overflow */
2904 else
2905 return SL_FALSE;
2906}
2907
[20]2908int sl_ok_subi (int a, int b) /* a-b */
2909{
2910 if (a >= 0 && b < 0)
2911 {
2912 if (a <= (INT_MAX + b))
2913 return SL_TRUE; /* no overflow */
2914 else
2915 return SL_FALSE;
2916 }
2917 else if (a < 0 && b >= 0)
2918 {
2919 if (a >= (INT_MIN + b))
2920 return SL_TRUE; /* no overflow */
2921 else
2922 return SL_FALSE;
2923 }
2924 return SL_TRUE;
2925}
Note: See TracBrowser for help on using the repository browser.