source: trunk/src/slib.c@ 526

Last change on this file since 526 was 525, checked in by katerina, 8 years ago

Log error if the close() on the baseline database fails (ticket #420).

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