source: trunk/src/slib.c@ 552

Last change on this file since 552 was 552, checked in by katerina, 5 years ago

Fix gcc 9.2.1 (Ubuntu 19.10) compiler warnings.

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