source: trunk/src/slib.c@ 500

Last change on this file since 500 was 481, checked in by katerina, 9 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

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