source: trunk/src/slib.c@ 479

Last change on this file since 479 was 476, checked in by katerina, 9 years ago

Fix for ticket #373 (better autoconf macro for va_copy).

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