source: trunk/src/slib.c@ 583

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

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

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